home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / src / energize.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-07  |  145.3 KB  |  5,439 lines

  1. /****************************************************************************
  2.  ***
  3.  ***    Copyright (c) 1990 by Sun/Lucid,    All Rights Reserved.
  4.  ***    Copyright (c) 1991-1993 by Lucid, Inc.  All Rights Reserved.
  5.  ***
  6.  *****************************************************************************/
  7.  
  8. /* Synched up with: Not in FSF. */
  9.  
  10. #include <config.h>
  11.  
  12. #ifdef ENERGIZE        /* whole file */
  13.  
  14. #include "lisp.h"
  15.  
  16. /* Display Context for the icons */
  17. #include "device-x.h"
  18. #include "frame-x.h"
  19. #include <Xm/DialogS.h>
  20. #include "lwlib.h"
  21. #include "objects-x.h"
  22.  
  23. #include "events.h"
  24. #include "opaque.h"
  25. #include "buffer.h"
  26. #include "extents.h"
  27. #include "process.h"
  28. #include "insdel.h"
  29. #include "window.h"
  30. #include "faces.h"
  31.  
  32. /* Energize editor requests and I/O operations */
  33. #include "energize.h"
  34.  
  35. #include "systime.h"
  36. #include "sysfile.h"
  37. #include "syssignal.h"
  38.  
  39. #ifndef CBFileYourself
  40. /* This means that emacs is being compiled against the connection library
  41.    and headers that go with an Energize protocol less than 0.10.  We need
  42.    to do some slightly different things in this file because of that.
  43.  
  44.    Note that if Emacs is compiled against the 3.0 version of the connection
  45.    library and associated headers, it can still talk to 2.1- or 2.5-level
  46.    servers.  But the opposite is not true.
  47.  */
  48. # define ENERGIZE_V2_HEADERS
  49. #endif
  50.  
  51. /* The Connection library
  52.  */
  53. extern void CWriteQueryChoicesRequest ();
  54. extern void CWriteExecuteChoicesRequest ();
  55. extern void CWriteSheetRequest ();
  56. extern void CWriteSetControlRequest ();
  57. extern void CWriteChoice ();
  58. extern void CWriteProtocol ();
  59. extern int  CGetPortNumber ();
  60.  
  61.  
  62. /************** Typedefs and Structs ***********************/
  63.  
  64. /* structure argument used by the next mapping function */
  65. typedef struct
  66. {
  67.   BufferInfo *binfo;
  68.   int n_extents;
  69. } binfo_and_n_extents;
  70.  
  71. typedef struct
  72. {
  73.   BufferInfo*    binfo;
  74.   int        state;
  75.   int        tell_energize;
  76. } binfo_and_state;
  77.  
  78. struct reply_wait
  79. {
  80.   int        serial;
  81.   EId        objectId;
  82.   EId        genericId;
  83.   EId        itemId;
  84.   char        answered_p;
  85.   char        status;
  86.   char*        message;
  87.   Lisp_Object    menu_result;
  88.   Lisp_Object    only_name;
  89.   struct reply_wait*    next;
  90. };
  91.  
  92. static struct reply_wait *global_reply_wait;
  93.  
  94. Lisp_Object Venergize_kernel_busy;
  95. Lisp_Object Qenergize_kernel_busy;
  96. Lisp_Object Venergize_attributes_mapping;
  97. int energize_extent_gc_threshold;
  98. Lisp_Object Venergize_kernel_busy_hook;
  99. Lisp_Object Qenergize_kernel_busy_hook;
  100. Lisp_Object Venergize_menu_update_hook;
  101. Lisp_Object Qenergize_menu_update_hook;
  102. Lisp_Object Qenergize;
  103. Lisp_Object Qenergize_auto_revert_buffer;
  104.  
  105.  
  106. static void set_energize_extent_data (EXTENT extent, void *data);
  107.  
  108. static char *kernel_buffer_type_to_elisp_type (char *kernel_type);
  109.  
  110. static CONST void *get_object (EId id, BufferInfo *binfo);
  111. static void put_object (EId id, BufferInfo *binfo, void *object);
  112. static void remove_object (EId id, BufferInfo *binfo);
  113. static void free_GDataclass (GDataClass *cl, BufferInfo *binfo);
  114.  
  115. static void free_GenericData (GenericData *gen, BufferInfo *binfo);
  116.  
  117. static void free_Energize_Extent_Data (Energize_Extent_Data *, BufferInfo *,
  118.                        enum Energize_Object_Free_Type);
  119.  
  120. static BufferInfo *get_buffer_info_for_emacs_buffer (Lisp_Object emacs_buf,
  121.                              Editor *editor);
  122. static void put_buffer_info (EId id, Lisp_Object emacs_buf,
  123.                  BufferInfo *binfo, Editor *editor);
  124.  
  125. static void handle_sheet_control_change (Widget, EId sheet_id, void* arg);
  126. static Connection *make_energize_connection (Editor *editor,
  127.                          int fdin, int fdout);
  128. static void close_energize_connection (void);
  129. Lisp_Object Fclose_connection_to_energize (void);
  130. static void mark_all_extents_as_unmodified (BufferInfo *binfo);
  131. Lisp_Object Fenergize_barf_if_buffer_locked (void);
  132. Lisp_Object Fconnected_to_energize_p (void);
  133. static int get_energize_connection_and_buffer_id (Lisp_Object buffer,
  134.                           void **conn_ptr,
  135.                           long *buffer_id_ptr);
  136.  
  137. void restore_energize_extent_state (EXTENT);
  138.  
  139.  
  140. /**************************** Variables *****************************/
  141.  
  142. /* debugging variable */
  143. int ignore_kernel;
  144.  
  145. Lisp_Object Venergize_kernel_modification_hook;
  146. Lisp_Object Venergize_create_buffer_hook;
  147. Lisp_Object Qenergize_create_buffer_hook;
  148.  
  149. Lisp_Object Qenergize_buffer_modified_hook;
  150. Lisp_Object Qbuffer_locked_by_energize;
  151. Lisp_Object Qenergize_user_input_buffer_mark;
  152. Lisp_Object Qenergize_make_many_buffers_visible;
  153.  
  154. int inside_parse_buffer;
  155.  
  156. /* List of all buffers currently managed by Energize.  This is
  157. Staticpro'ed so that they don't get GC'ed from under us. */
  158. static Lisp_Object Venergize_buffers_list;
  159.  
  160. static Editor *energize_connection;
  161. static protocol_edit_options *peo;
  162.  
  163. static int request_serial_number;
  164.  
  165. extern int current_debuggerpanel_exposed_p;
  166. extern int desired_debuggerpanel_exposed_p;
  167. extern int debuggerpanel_sheet;
  168.  
  169. /**************************** Macros *****************************/
  170.  
  171. #define xnew(type) ((type*)xmalloc (sizeof (type)))
  172.  
  173. #define BUFFER_NOTIFY_BACKGROUND_BIT_SET_P(buffer) 1
  174.  
  175. #define get_extent_data(id,binfo) (Energize_Extent_Data*)get_object(id, binfo)
  176. #define get_class(id,binfo) (GDataClass*)get_object(id, binfo)
  177. #define get_generic(id,binfo) (GenericData*)get_object(id, binfo)
  178.  
  179. #define put_extent_data(id,binfo,obj) put_object(id, binfo, obj)
  180. #define put_class(id,binfo,obj) put_object(id, binfo, obj)
  181. #define put_generic(id,binfo,obj) put_object(id, binfo, obj)
  182.  
  183. #define remove_extent_data(id,binfo) remove_object(id, binfo)
  184. #define remove_class(id,binfo) remove_object(id, binfo)
  185. #define remove_generic(id,binfo) remove_object(id, binfo)
  186.  
  187. #define DEBUGGER_PSHEET_NAME  "DEBUGGER_P_SHEET"
  188.  
  189. /* special graphics attribute meaning "use what anyone else's attributes" */
  190. #define GA_NO_CHANGE 0
  191. /* this number should be bigger than any of the "real" GA's */
  192. #define GA_MAX 0x1000
  193.  
  194. /**************************** Utilities *****************************/
  195.  
  196. static int
  197. emacs_CWriteRequestBuffer (Connection* conn)
  198. {
  199.   int result;
  200.   /* don't kill emacs with SIGPIPE */
  201.   SIGTYPE (*old_sigpipe)() =
  202.     (SIGTYPE (*) ()) signal (SIGPIPE, SIG_IGN);
  203.  
  204.   result = CWriteRequestBuffer (conn);    /* the real one; macroized later */
  205.   signal (SIGPIPE, old_sigpipe);
  206.   return result;
  207. }
  208.  
  209. #define CWriteRequestBuffer emacs_CWriteRequestBuffer
  210.  
  211.  
  212. static Energize_Extent_Data *
  213. extent_to_data (Lisp_Object extent_obj)
  214. {
  215.   Energize_Extent_Data *ext = 0;
  216.  
  217.   if (!EXTENTP (extent_obj))
  218.     return 0;
  219.   else
  220.     ext = energize_extent_data (XEXTENT (extent_obj));
  221.  
  222.   if (ext)
  223.     {
  224.       if (EQ (ext->extent, extent_obj))
  225.     return ext;
  226.       else
  227.     abort ();
  228.     }
  229.   else
  230.     return 0;
  231. }
  232.  
  233.  
  234. static Lisp_Object
  235. data_to_extent (Energize_Extent_Data *ext)
  236. {
  237.   Lisp_Object extent = ext->extent;
  238.   assert (EXTENTP (extent));
  239.   return extent;
  240. }
  241.  
  242. /* duplicate a string */
  243. static char*
  244. copy_string (char *s)
  245. {
  246.   if (!s)
  247.     return 0;
  248.   else
  249.     {
  250.       int len = strlen (s);
  251.       char *res = (char *) xmalloc (len + 1);
  252.       return strcpy (res, s);
  253.     }
  254. }
  255.  
  256. /* Get objects from the hashtables */
  257. static CONST void *
  258. get_object_internal (EId id, c_hashtable table)
  259. {
  260.   void *res;
  261.   CONST void *found = gethash ((void*)id, table, &res);
  262.  
  263.   if (found) CHECK_OBJECT (res, 0);
  264.  
  265.   return found ? res : 0;
  266. }
  267.  
  268. static CONST void *
  269. get_object (EId id, BufferInfo *binfo)
  270. {
  271.   return get_object_internal (id, binfo->id_to_object);
  272. }
  273.  
  274. static void
  275. put_object_internal (EId id, c_hashtable table, void *object)
  276. {
  277.   if (!PUT_ABLE_OBJECT (object))
  278.     error ("Can't put 0x%x in table", object);
  279.   CHECK_OBJECT (object, 0);
  280.   puthash ((void*)id, object, table);
  281. }
  282.  
  283. static void
  284. put_object (EId id, BufferInfo *binfo, void *object)
  285. {
  286.   put_object_internal (id, binfo->id_to_object, object);
  287.   return;
  288. }
  289.  
  290. static void
  291. remove_object_internal (EId id, c_hashtable table)
  292. {
  293.   void *res;
  294.  
  295.   if (gethash ((void*)id, table, &res))
  296.     {
  297.       if (OBJECT_FREE (res))
  298.     error ("Free'd object 0x%x still in table!", res);
  299.       remhash ((void*)id, table);
  300.     }
  301.   else if (id)
  302.     /* #### If this happens for Energize_Extent_Data as a result of extent
  303.        finalization, this aborts (because gc_in_progress).  These errors are
  304.        awfully bad, so probably they should just be abort()s anyway... */
  305.     error ("EId %d not in table!", id);
  306. }
  307.  
  308. static void
  309. remove_object (EId id, BufferInfo *binfo)
  310. {
  311.   remove_object_internal (id, binfo->id_to_object);
  312.   return;
  313. }
  314.  
  315. /* maphash_function called by free_buffer_info */
  316. static void
  317. free_object (void *key, void *contents, void *arg)
  318. {
  319.   BufferInfo *binfo = arg;
  320.  
  321.   if (contents)
  322.     {
  323.       switch (OBJECT_SEAL (contents))
  324.     {
  325.     case BUF_INFO_SEAL:
  326.       break;
  327.     case EXTENT_SEAL:
  328.       free_Energize_Extent_Data ((Energize_Extent_Data *) contents,
  329.                      binfo, OFT_MAPHASH);
  330.       break;
  331.     case GDATA_CLASS_SEAL:
  332.       free_GDataclass ((GDataClass *) contents, binfo);
  333.       break;
  334.     case GDATA_SEAL:
  335.       free_GenericData ((GenericData *) contents, binfo);
  336.       break;
  337.     default:
  338.       error ("Bad argument 0x%x to free_object()", contents);
  339.       return;
  340.     }
  341.     }
  342. }
  343.  
  344. static GDataClass *
  345. alloc_GDataclass (EId id, BufferInfo *binfo)
  346. {
  347.   GDataClass *cl = xnew (GDataClass);
  348.   memset (cl, 0, sizeof (GDataClass));
  349.   cl->seal = GDATA_CLASS_SEAL;
  350.   cl->id = id;
  351.   put_class (cl->id, binfo, cl);
  352.   return cl;
  353. }
  354.  
  355. static void
  356. free_GDataclass (GDataClass *cl, BufferInfo *binfo)
  357. {
  358.   if (cl)
  359.     {
  360.       remove_class (cl->id, binfo);
  361.       SET_OBJECT_FREE (cl);
  362.     }
  363.   return;
  364. }
  365.  
  366.  
  367. static GenericData *
  368. alloc_GenericData (EId id, GDataClass *cl, BufferInfo *binfo)
  369. {
  370.   GenericData *gen = xnew (GenericData);
  371.   gen->seal = GDATA_SEAL;
  372.   gen->id = id;
  373.   gen->cl = cl;
  374. /*  gen->image = 0;*/
  375.   gen->flags = 0;
  376.   gen->modified_state = 0;
  377.   put_generic (gen->id, binfo, gen);
  378.   return gen;
  379. }
  380.  
  381. static void
  382. free_GenericData (GenericData *gen, BufferInfo *binfo)
  383. {
  384.   if (gen)
  385.     {
  386.       remove_generic (gen->id, binfo);
  387.       gen->cl = 0;
  388.       SET_OBJECT_FREE (gen);
  389.     }
  390.   return;
  391. }
  392.  
  393. /* Called to flush the extent from the hash table when Energize tells us to
  394.    lose the extent.  This is NOT called from the extent GC finalization method,
  395.    because there would be a period before the next GC when we still had an
  396.    Energize ID that the server thought was dead, and could concievably reuse.
  397.  
  398.    Since we protect extents from GC until Energize says they're done, if an
  399.    extent still has Energize data by the time it gets collected, something is
  400.    fucked.
  401.  */
  402. static void
  403. free_Energize_Extent_Data (Energize_Extent_Data *ext, BufferInfo *binfo,
  404.                enum Energize_Object_Free_Type free_type)
  405. {
  406.   if (ext)
  407.     {
  408.       Lisp_Object extent_obj = data_to_extent (ext);
  409.  
  410.       /* Remove the extent, remove the extent's pointer to the data,
  411.      and the data's pointer to the extent. */
  412.       Fdetach_extent (extent_obj);
  413.       set_energize_extent_data (XEXTENT (extent_obj), 0);
  414.       ext->extent = Qnil; /* at this point, refs will abort */
  415.  
  416.       /* Remove the data from the hash table, and mark it as dead. */
  417.       remove_extent_data (ext->id, binfo);
  418.       ext->id = 0;
  419.  
  420.       /* don't free this "sub-guy" via maphash, as it will get taken care
  421.      of during the course of the maphash without our doing anything */
  422.       if (free_type != OFT_MAPHASH)
  423.     {
  424.       if (ext->extentType == CEGeneric)
  425.         free_GenericData (ext->u.generic.gData, binfo);
  426.     }
  427.  
  428.       SET_OBJECT_FREE (ext);
  429.     }
  430.   return;
  431. }
  432.  
  433. void
  434. energize_extent_finalization (EXTENT extent)
  435. {
  436.   /* In the new world, extents are protected from GC until Energize is
  437.      done with them, so if we GC an extent that still has Energize
  438.      data, that means the extents weren't properly protected. */
  439.   /*
  440.      Except that in the even newer world, we can't do this check because the
  441.      Energize_Extent_Data is pointed to by a cons that may have been collected
  442.      already, so CDRing down the extent->plist can crash.  Oh well.
  443.  
  444.   Energize_Extent_Data *ext = energize_extent_data (extent);
  445.   if (ext) abort ();
  446.   */
  447. }
  448.  
  449. static BufferInfo *
  450. alloc_BufferInfo (EId id, Lisp_Object name, Lisp_Object filename,
  451.           char *class_str, Editor *editor, Window win, int nobjects)
  452. {
  453.   BufferInfo *binfo = xnew (BufferInfo);
  454.   Widget nw = 0;
  455.   Lisp_Object buffer = Qnil;
  456.  
  457.   if (win)
  458.     {
  459.       char win_as_string [16];
  460.       nw = XtWindowToWidget (get_x_display (Qnil), win);
  461.       if (nw)
  462.     nw = XtParent (nw);
  463.       
  464.       if (nw)
  465.     sprintf (win_as_string, "w%x", nw);
  466.       else
  467.     sprintf (win_as_string, "0x%x", win);
  468.       binfo->frame =
  469.     Fx_create_frame (Qnil, Qnil, build_string (win_as_string));
  470.     }
  471.   else
  472.     binfo->frame = Qnil;
  473.  
  474.   /* try to re-use a buffer with the same file name if one already exists.
  475.    * If a buffer already exists but is modified we should do a dialog and
  476.    * ask the user what to do.  For now I'll just use a new buffer in that case.
  477.    * ParseBuffer will erase the buffer.
  478.    */
  479.   if (!NILP (filename))
  480.     {
  481.       int offct = find_file_compare_truenames;
  482.       find_file_compare_truenames = 1;
  483.       buffer = Fget_file_buffer (filename);
  484.       find_file_compare_truenames = offct;
  485.  
  486.       if (!NILP (buffer) && !NILP (Fbuffer_modified_p (buffer)))
  487.     buffer = Qnil;
  488.     }
  489.  
  490.   if (NILP (buffer))
  491.     buffer = Fget_buffer_create (Fgenerate_new_buffer_name (name, Qnil));
  492.  
  493.   binfo->seal = BUF_INFO_SEAL;
  494.   binfo->id = id;
  495.   binfo->flags = 0;
  496.   binfo->editor = editor;
  497.   binfo->id_to_object = make_hashtable (nobjects);
  498.   binfo->emacs_buffer = buffer;
  499.   binfo->modified_state = 0;
  500.   binfo->editable = 0;
  501.   binfo->output_mark = Qnil;
  502.   binfo->buffer_type = kernel_buffer_type_to_elisp_type (class_str);
  503.   binfo->p_sheet_ids = 0;
  504.   binfo->n_p_sheets = 0;
  505.   binfo->note_ids = 0;
  506.   binfo->n_notes = 0;
  507. #ifdef I18N4
  508.   binfo->wcmap.valid = 0;
  509.   binfo->wcmap.modiff_stamp = -1;
  510.   binfo->wcmap.map = NULL;
  511. #endif   
  512.   put_buffer_info (id, binfo->emacs_buffer, binfo, editor);
  513.  
  514.   Venergize_buffers_list = Fcons (buffer, Venergize_buffers_list);
  515.  
  516. #if 0
  517.  *  if (nw){
  518.  *    Lisp_Object window = Fframe_selected_window (binfo->frame);
  519.  *    Fset_window_buffer (window, binfo->emacs_buffer);
  520.  *    set_text_widget ((NoteWidget)nw,
  521.  *             FRAME_X_SHELL_WIDGET (XFRAME (binfo->frame)));
  522.  *  }
  523. #endif
  524.  
  525.   return binfo;
  526. }
  527.  
  528. /* free a buffer_info */
  529. static void
  530. free_buffer_info (BufferInfo *binfo)
  531. {
  532.   maphash (free_object, binfo->id_to_object, (void *)binfo);
  533.   free_hashtable (binfo->id_to_object);
  534.   if (energize_connection && energize_connection->binfo_hash)
  535.     {
  536.       if (binfo->id)
  537.     remhash ((void *)binfo->id, energize_connection->binfo_hash);
  538.       if (!NILP (binfo->emacs_buffer))
  539.     {
  540.       remhash (LISP_TO_VOID (binfo->emacs_buffer),
  541.            energize_connection->binfo_hash);
  542.     }
  543.     }
  544.   binfo->id = 0;
  545.   binfo->emacs_buffer = Qnil;
  546. #ifdef I18N4
  547.   if (binfo->wcmap.valid) {
  548.     binfo->wcmap.valid= 0;
  549.     xfree(binfo->wcmap.map);
  550.   }
  551. #endif 
  552.   SET_OBJECT_FREE (binfo);
  553. }
  554.  
  555. /* hash for BufferInfo structures */
  556. static BufferInfo*
  557. get_buffer_info_for_emacs_buffer (Lisp_Object emacs_buf, Editor *editor)
  558. {
  559.   BufferInfo *res;
  560.   if (!editor || !editor->binfo_hash)
  561.     return 0;
  562.   else
  563.     {
  564.       void *vbuf;
  565.       /* #### Probably should use a Lisp hash table for this; what if the last
  566.      pointer to the buffer was in the editor struct? */
  567.       return (gethash (LISP_TO_VOID (emacs_buf),
  568.                editor->binfo_hash,
  569.                (void *) &res)
  570.           ? res : 0);
  571.     }
  572. }
  573.  
  574.  
  575.  
  576. /* Called by mark_buffer.  It is possible for the last remaining pointer to
  577.    an extent object to be in an Energize_Extent_Data structure that is pointed
  578.    at by the binfo->id_to_object table.  Since Energize may still reference
  579.    this object by its id (in fact, I think it may even "ressurect" a detached
  580.    extent) we must prevent the extent from being garbage collected.  Aside 
  581.    from the obvious lossage (that the extent itself would be trashed) this
  582.    would also cause us to free the Energize_Extent_Data which the server still
  583.    believes we have.  The buffers all get marked because they're on the
  584.    `Venergize_buffers_list'.
  585.  
  586.    So, an Energize extent or buffer only ever gets collected when the server
  587.    has claimed that it is done with it (or when the connection is closed).
  588.  
  589.    Of course, by keeping pointers to lisp objects in C structs under non-lisp
  590.    hash tables, we again build in the assumption that GC never relocates.
  591.  */
  592.  
  593. /* FUCK!!  It's not standard-conforming to cast pointers to functions
  594.    to or from void*.  Give me a fucking break! */
  595. struct markobj_kludge_fmh 
  596. {
  597.   void (*markobj) (Lisp_Object);
  598. };
  599.  
  600. static void
  601. mark_energize_buffer_data_extent_mapper (void *key, void *val, void *arg)
  602. {
  603.   if (OBJECT_SEAL (val) == EXTENT_SEAL)
  604.     {
  605.       struct markobj_kludge_fmh *fmh = arg;
  606.       struct Energize_Extent_Data *ext = (Energize_Extent_Data *) val;
  607.       /* Lisp_Object extent = data_to_extent (ext);  (will abort if marked) */
  608.       Lisp_Object extent = ext->extent;
  609.       assert (gc_record_type_p (extent, lrecord_extent));
  610.       ((*fmh->markobj) (extent));
  611.     }
  612. }
  613.  
  614. void
  615. mark_energize_buffer_data (struct buffer *b,
  616.                void (*markobj) (Lisp_Object))
  617. {
  618.   struct markobj_kludge_fmh fmh;
  619.   Lisp_Object buffer;
  620.   BufferInfo *binfo;
  621.   if (!energize_connection || !energize_connection->binfo_hash)
  622.     return;
  623.   XSETBUFFER (buffer, b);
  624.   binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
  625.   if (! binfo)
  626.     return;
  627.   fmh.markobj = markobj;
  628.   maphash (mark_energize_buffer_data_extent_mapper, binfo->id_to_object, &fmh);
  629. }
  630.  
  631.  
  632.  
  633. struct buffer_and_sheet_ids
  634. {
  635.   EId    buffer_id;
  636.   EId    sheet_id;
  637. };
  638.  
  639. static void
  640. find_sheet_id (void* key, void* contents, void* arg)
  641. {
  642.   BufferInfo* binfo = (BufferInfo*)contents;
  643.   EId buffer_id = (EId)key;
  644.   struct buffer_and_sheet_ids* result = (struct buffer_and_sheet_ids*)arg;
  645.   int i;
  646.  
  647.   if (!result->buffer_id)
  648.     for (i = 0; i < binfo->n_p_sheets; i++)
  649.       if (binfo->p_sheet_ids [i] == result->sheet_id)
  650.     {
  651.       result->buffer_id = buffer_id;
  652.       return;
  653.     }
  654. }
  655.  
  656. static EId
  657. buffer_id_of_sheet (EId id)
  658. {
  659.   Editor *editor = energize_connection;
  660.   struct buffer_and_sheet_ids basi;
  661.   if (!energize_connection)
  662.     return 0;
  663.  
  664.   basi.buffer_id = 0;
  665.   basi.sheet_id = id;
  666.   maphash (find_sheet_id, editor->binfo_hash, (void*)&basi);
  667.   return basi.buffer_id;
  668. }
  669.  
  670. static long
  671. get_energize_buffer_id (Lisp_Object emacs_buf)
  672. {
  673.   Editor *editor = energize_connection;
  674.   BufferInfo *res;
  675.  
  676.   if (!editor || !editor->binfo_hash)
  677.     return -1;
  678.   else if (!gethash (LISP_TO_VOID (emacs_buf), editor->binfo_hash, (void *)&res))
  679.     return -1;
  680.   else
  681.     return (long) res->id;
  682. }
  683.  
  684. static char *
  685. kernel_buffer_type_to_elisp_type (char *kernel_type)
  686. {
  687.   struct buffer_type_struct *bts =
  688.     kernel_buffer_types_to_elisp_buffer_types_vector;
  689.   char *elisp_type = 0;
  690.  
  691.   if (!kernel_type)
  692.     return UNINITIALIZED_BUFFER_TYPE;
  693.  
  694.   while (bts->kernel_name)
  695.     {
  696.       if (!strcmp (bts->kernel_name, kernel_type))
  697.     {
  698.       elisp_type = bts->elisp_name;
  699.       break;
  700.     }
  701.       bts++;
  702.     }
  703.  
  704.   if (!elisp_type)
  705.     return kernel_type;
  706.   else
  707.     return elisp_type;
  708. }
  709.  
  710. static Lisp_Object
  711. get_buffer_type_for_emacs_buffer (Lisp_Object emacs_buf, Editor *editor)
  712. {
  713.   BufferInfo *binfo;
  714.   if (!(binfo = get_buffer_info_for_emacs_buffer (emacs_buf, editor)))
  715.     return Qnil;
  716.   else
  717.     {
  718.       if (!binfo->buffer_type) binfo->buffer_type =
  719.     UNINITIALIZED_BUFFER_TYPE;
  720.  
  721.       return intern (binfo->buffer_type);
  722.     }
  723. }
  724.  
  725. static Lisp_Object
  726. set_buffer_type_for_emacs_buffer (Lisp_Object emacs_buf, Editor *editor,
  727.                     Lisp_Object type)
  728. {
  729.   BufferInfo *binfo;
  730.   if (!(binfo = get_buffer_info_for_emacs_buffer (emacs_buf, editor)))
  731.     return Qnil;
  732.   else
  733.     {
  734.       char *type_string;
  735.  
  736.       if (NILP (type)) return Qnil;
  737.  
  738.       if (SYMBOLP (type))
  739.     XSETSTRING (type, XSYMBOL (type)->name);
  740.  
  741.       if (STRINGP (type))
  742.     type_string = (char *)string_data (XSTRING (type));
  743.  
  744.       type_string = copy_string (type_string);
  745.  
  746.       if (!type_string) return Qnil;
  747.  
  748.       binfo->buffer_type = type_string;
  749.  
  750.       return intern (binfo->buffer_type);
  751.     }
  752. }
  753.  
  754. static BufferInfo*
  755. get_buffer_info_for_id (EId id, Editor *editor)
  756. {
  757.   BufferInfo *res;
  758.   return (gethash ((void *)id, editor->binfo_hash, (void *)&res))?res:0;
  759. }
  760.  
  761. static void
  762. put_buffer_info (EId id, Lisp_Object emacs_buf, BufferInfo *binfo,
  763.          Editor *editor)
  764. {
  765.   puthash ((void *)id, binfo, editor->binfo_hash);
  766.   puthash (LISP_TO_VOID (emacs_buf), binfo, editor->binfo_hash);
  767. }
  768.  
  769. static void
  770. remove_buffer_info (EId id, Lisp_Object emacs_buf, Editor *editor)
  771. {
  772.   void *vbuf;
  773.   remhash ((void *)id, editor->binfo_hash);
  774.   remhash (LISP_TO_VOID (emacs_buf), editor->binfo_hash);
  775. }
  776.  
  777.  
  778. /* Conversion between Energize and Emacs buffer positions */
  779.  
  780. #if defined(I18N4)
  781.  
  782. /* An emacs position is an index into the buffer...  In I18N, foreign
  783.    characters take up the same amount of space as ASCII characters.  Emacs
  784.    is using wide characters.  The first position is 1.
  785.  
  786.    An energize position is a straight byte offset into the file when it's
  787.    saved onto disk.  Foreign characters take up more than one byte.  The
  788.    first position is 0. */
  789.  
  790. #define WCMAP_SETSIZE(wcmap,n) {                          \
  791.   (wcmap).mapsize = (n);                              \
  792.   (wcmap).map = (WCharMapRec *) xrealloc((wcmap).map,                  \
  793.                      (n) * sizeof(WCharMapRec));          \
  794. }
  795. #define WCMAP_ENLARGE(wcmap) WCMAP_SETSIZE(wcmap, 2*(wcmap.mapsize))
  796.  
  797. #ifndef MB_LEN_MAX
  798. #define MB_LEN_MAX 10        /* arbitrarily large enough */
  799. #endif 
  800.  
  801. static char wcsize_buf[MB_LEN_MAX];
  802. #define WCSIZE(wc)         (isascii(wc) ? 1 : wctomb(wcsize_buf,wc))
  803.  
  804. #define SANITY_CHECK_NOT
  805. #ifdef SANITY_CHECK
  806. static int sanity=0;
  807. #endif 
  808.  
  809. static void
  810. sync_buffer_widechar_map (BufferInfo *binfo)
  811. {
  812.   /* #### - check this: */
  813.   assert (XBUFFER (binfo->emacs_buffer) == current_buffer);
  814.  
  815.   if (!binfo->wcmap.valid)
  816.     {
  817.       binfo->wcmap.valid= 1;
  818.       binfo->wcmap.modiff_stamp= -1;
  819.       binfo->wcmap.map= NULL;
  820.       WCMAP_SETSIZE (binfo->wcmap, 1);
  821.     }
  822.  
  823.   if (binfo->wcmap.modiff_stamp == BUF_MODIFF (current_buffer))
  824.     {
  825.       return;
  826.     }
  827.   else
  828.     {
  829.       int nbytes, maxpos,
  830.       pos = 0,            /* start at zero instead of 1 */
  831.       adjustment = 0,
  832.       mapindex= 0;
  833.       wchar_t *buf, t;
  834.  
  835. #ifdef SANITY_CHECK
  836.       stderr_out ("rebuilding widechar map for %s\n", string_data (XSTRING (current_buffer->name)));
  837. #endif
  838.       
  839.       /* #### this is not gonna compile.  move_gap() is now a private function
  840.      inside of insdel.c and it should stay that way. */
  841.       if (BUF_BEGV (current_buffer) < GPT && BUF_ZV (current_buffer) > GPT)
  842.     move_gap (current_buffer, BUF_BEGV (current_buffer));
  843.       binfo->wcmap.modiff_stamp = BUF_MODIFF (current_buffer);
  844.       
  845.       buf = BUF_BEG_ADDR (current_buffer);
  846.       maxpos= (BUF_Z (current_buffer) - 1);
  847.       wctomb (NULL, 0);        /* reset shift state of wctomb() */
  848.       binfo->wcmap.map[mapindex].pos= pos;
  849.       binfo->wcmap.map[mapindex].eucsize=
  850.     ((pos<maxpos) ? (nbytes= WCSIZE(buf[pos])) : 1);
  851.       do {
  852.     while ((pos < maxpos) && (nbytes == WCSIZE(t = buf[pos])))
  853.       ++pos;
  854.     binfo->wcmap.map[mapindex++].endpos= pos;
  855.     if (mapindex == binfo->wcmap.mapsize)
  856.       WCMAP_ENLARGE(binfo->wcmap);
  857.     if (pos < maxpos)
  858.       {
  859.         binfo->wcmap.map[mapindex].pos= pos;
  860.         binfo->wcmap.map[mapindex].eucsize= nbytes= WCSIZE(t);
  861.       }
  862.       } while (pos < maxpos);
  863.       WCMAP_SETSIZE(binfo->wcmap, mapindex);
  864.     }
  865. }
  866.  
  867. static EnergizePos
  868. EnergizePosForBufpos (Bufpos char_pos, BufferInfo *binfo)
  869. {
  870.   int mapindex;
  871.   WCharMapRec map;
  872.   EnergizePos byte_pos;
  873.  
  874.   sync_buffer_widechar_map (binfo);
  875.  
  876.   --char_pos;            /* preadjust emacs position */
  877.  
  878.   mapindex=0, byte_pos=0;
  879.   while ((mapindex < binfo->wcmap.mapsize) &&
  880.      (char_pos > (map= binfo->wcmap.map[mapindex++]).pos)) {
  881.     if (char_pos > map.endpos) {
  882.       byte_pos += ((map.endpos - map.pos) * map.eucsize);
  883.     } else {
  884.       byte_pos += ((char_pos - map.pos) * map.eucsize);
  885.     }
  886.   }
  887.   /* there should be a sanity check here */
  888. #ifdef CHECK_SANITY
  889.   if (!sanity) {
  890.     Bufpos check_pos;
  891.     sanity=1;
  892.     check_pos= BufposForEnergizePos(byte_pos, binfo);
  893.     sanity=0;
  894.  
  895.     if (check_pos != char_pos) {
  896.       stderr_out ("ezpos(%d) = %d, Bufpos(%d) = %d\n",
  897.           char_pos, byte_pos, byte_pos, check_pos);
  898.     }
  899.   }
  900. #endif 
  901.   return byte_pos;
  902. }
  903.  
  904. static Bufpos
  905. BufposForEnergizePos (EnergizePos ez_pos, BufferInfo *binfo)
  906. {
  907.   int mapindex, x;
  908.   WCharMapRec map;
  909.   Bufpos char_pos;
  910.   EnergizePos byte_pos;
  911.  
  912.   sync_buffer_widechar_map(binfo);
  913.  
  914.   mapindex=0, byte_pos=0;
  915.   while ((mapindex < binfo->wcmap.mapsize) &&
  916.      (byte_pos <= ez_pos)) {
  917.     map= binfo->wcmap.map[mapindex++];
  918.     x= (map.eucsize*(map.endpos-map.pos));
  919.     if (ez_pos > (byte_pos + x)) {
  920.       byte_pos += x;
  921.       char_pos = map.endpos;
  922.     } else {
  923.       char_pos = (map.pos + ((ez_pos - byte_pos)/map.eucsize));
  924.       break;
  925.     }
  926.   }
  927.   char_pos= (char_pos >= (1 << VALBITS)) ? BUF_Z (current_buffer) :
  928.     (char_pos + 1);
  929. #ifdef CHECK_SANITY
  930.   if (!sanity) {
  931.     EnergizePos check_pos;
  932.     sanity=1;
  933.     check_pos= EnergizePosForBufpos(char_pos);
  934.     sanity=0;
  935.     
  936.     if (check_pos != ez_pos) {
  937.       stderr_out ("Bufpos(%d) = %d, EnergizePosForBufpos(%d) = %d\n",
  938.           ez_pos, char_pos, char_pos, check_pos);
  939.     }
  940.   }
  941. #endif 
  942.   return (char_pos);
  943. }
  944.  
  945. #else /* !I18N4 */
  946.  
  947. static Bufpos
  948. BufposForEnergizePos (EnergizePos energizePos, BufferInfo *binfo)
  949. {
  950.   return ((energizePos >= (1 << VALBITS)) ? BUF_Z (current_buffer) : 
  951.       (energizePos + 1));
  952. }
  953.  
  954. static EnergizePos
  955. EnergizePosForBufpos (Bufpos emacs_pos, BufferInfo *binfo)
  956. {
  957.   return (emacs_pos - 1);
  958. }
  959.  
  960. #endif /* !I18N4 */
  961.  
  962. /* extent data */
  963.  
  964. Energize_Extent_Data *
  965. energize_extent_data (EXTENT extent)
  966. {
  967.   Lisp_Object data = extent_getf (extent, Qenergize);
  968.   if (NILP (data))
  969.     return 0;
  970.   return ((Energize_Extent_Data *) get_opaque_ptr (data));
  971. }
  972.  
  973. static void
  974. set_energize_extent_data (EXTENT e, void *data)
  975. {
  976.   extent_putf (e, Qenergize, make_opaque_ptr (data));
  977. }
  978.  
  979.  
  980. DEFUN ("energize-update-menubar", Fenergize_update_menubar,
  981.        Senergize_update_menubar, 0, 1, 0,
  982.        "obsolete")
  983.      (frame)
  984.      Lisp_Object frame;
  985. {
  986.   return Qnil;
  987. }
  988.  
  989.  
  990. DEFUN ("energize-extent-menu-p", Fenergize_extent_menu_p,
  991.        Senergize_extent_menu_p, 1, 1, 0,
  992.        "Whether the extent has a set of commands defined by Energize.")
  993.      (extent_obj)
  994.      Lisp_Object extent_obj;
  995. {
  996.   CHECK_EXTENT (extent_obj, 0);
  997.  
  998.   if (NILP (Fconnected_to_energize_p ()))
  999.     return Qnil;
  1000.   else
  1001.     {
  1002.       Energize_Extent_Data *ext = extent_to_data (extent_obj);
  1003.       return (ext && ext->extentType == CEGeneric) ? Qt : Qnil;
  1004.     }
  1005. }
  1006.  
  1007.  
  1008. /* Do what is needed so that the delayed requests will be notified by
  1009. ** the event loop */
  1010.  
  1011. extern void mark_process_as_being_ready (struct Lisp_Process* process);
  1012.  
  1013. static void
  1014. notify_delayed_requests (void)
  1015. {
  1016.   if (energize_connection
  1017.       && !NILP (energize_connection->proc)
  1018.       && energize_connection->conn
  1019.       && CRequestDelayedP (energize_connection->conn))
  1020.     this function no longer exists. 
  1021.     (Replaced by mark_what_as_being_ready, with different arguments.)
  1022.     Rewrite this.
  1023.     mark_process_as_being_ready (XPROCESS (energize_connection->proc));
  1024. }
  1025.  
  1026.  
  1027. /******************* IMAGE storage maintenance *******************/
  1028.  
  1029. extern GLYPH image_instance_to_glyph (Lisp_Object);
  1030.  
  1031. static c_hashtable image_cache;
  1032.  
  1033. extern char *strdup ();
  1034. extern Lisp_Object Fbuffer_file_name (Lisp_Object);
  1035.  
  1036.  
  1037. extern Lisp_Object Fmake_face (Lisp_Object name);
  1038. extern Lisp_Object Fface_foreground (Lisp_Object face, Lisp_Object frame);
  1039. extern Lisp_Object Fface_background (Lisp_Object face, Lisp_Object frame);
  1040.  
  1041. /* Don't let any of these get GCed, since we hold their GLYPH ids in
  1042.    a non-lisp hash table (image_cache) . */
  1043. static Lisp_Object Vall_energize_pixmaps;
  1044.  
  1045. /* Parses an image from the image language */
  1046. static GLYPH
  1047. read_energize_image_data (Connection *conn, BufferInfo *binfo)
  1048. {
  1049.   ReqLen l;
  1050.   char *s = CGetVstring (conn, &l);
  1051.   char pix_name [255];
  1052.   char buf [255];
  1053.   int attr_number, pix_len;
  1054.   char *file;
  1055.   GLYPH result = 0;
  1056.   /* It is bad news to pass the address of a short to gethash. */
  1057.   int hashed = 0;
  1058.  
  1059.   if (s[0] != 'f')
  1060.     return 0;
  1061.  
  1062.   if (gethash ((void *) s, image_cache, (void *) &hashed))
  1063.     /* If we have already parsed this image spec (string=) then just return
  1064.        the old glyph, instead of calling the lisp code, x_get_pixmap, and
  1065.        XtGetSubResources again.     The result may be 0 if there is no pixmap
  1066.        file name in the resource database.
  1067.      */
  1068.     return (GLYPH) hashed;
  1069.  
  1070.   if (3 != sscanf (s, "f %d p %d %s", &attr_number, &pix_len, pix_name))
  1071.     {
  1072.       sprintf (buf, "unparsable image: \"%s\"", s);
  1073.       error (buf);
  1074.     }
  1075.  
  1076.   assert (pix_len == strlen (pix_name));
  1077.  
  1078.   /* Read the pixmap file name for this image from the resource db */
  1079.   {
  1080.     XtResource resource [1];
  1081.     resource[0].resource_name = pix_name;
  1082.     resource[0].resource_class = XtCBitmap;
  1083.     resource[0].resource_type = XtRString;
  1084.     resource[0].resource_size = sizeof (char *);
  1085.     resource[0].resource_offset = 0;
  1086.     resource[0].default_type = XtRImmediate;
  1087.     resource[0].default_addr = 0;
  1088.     file = 0;
  1089.     XtGetSubresources (FRAME_X_SHELL_WIDGET (XFRAME (Fselected_frame (Qnil))),
  1090.                (XtPointer) &file, "image", "Image", resource, 1, NULL,
  1091.                0);
  1092.   }
  1093.  
  1094.   if (! file)
  1095.     result = 0;
  1096.   else
  1097.     {
  1098.       Lisp_Object lfile = Qnil;
  1099.       Lisp_Object p = Qnil;
  1100.       struct gcpro gcpro1, gcpro2;
  1101.       sprintf (buf, "attribute%d", attr_number);
  1102.       GCPRO2 (lfile, p);
  1103.       lfile = build_string (file);
  1104.       p = Fmake_image_instance (lfile, Qnil); /* may gc */
  1105.       result = image_instance_to_glyph (p);
  1106.       Vall_energize_pixmaps = Fcons (Fcons (make_number (result), p),
  1107.                      Vall_energize_pixmaps);
  1108.       if (!EQ (p, glyph_to_image_instance (result)))
  1109.     abort ();
  1110.       UNGCPRO;
  1111.  
  1112.       if (XIMAGE_INSTANCE (p)->depth == 0)
  1113.     /* if depth is >0 then this is an XPM, and its colors are not
  1114.        controlled by the fg/bg of a face.  So don't bother making a
  1115.        face for it. */
  1116.     {
  1117.       Lisp_Object face, fg, bg;
  1118.       struct face *c_face;
  1119.       /* #### review this */
  1120.       face = Fmake_face (intern (buf));
  1121.       fg = FACE_FOREGROUND (face, Qnil);
  1122.       bg = FACE_BACKGROUND (face, Qnil);
  1123.       Fcolorize_image_instance (p, fg, bg);
  1124.     }
  1125.     }
  1126.  
  1127.   /* CGetVstring returns a pointer into the connection buffer; we need to
  1128.      copy it to use it as a hash key. */
  1129.   s = strdup (s);
  1130.  
  1131.   hashed = result;
  1132.   puthash ((void *) s, (void *) hashed, image_cache);
  1133.   return result;
  1134. }
  1135.  
  1136.  
  1137. /* Parses Classes from the connection buffer.  Defines them for
  1138.  * the buffer given as argument */
  1139. static void
  1140. read_energize_class_data (Connection *conn, unsigned int number,
  1141.               BufferInfo *binfo, unsigned int modify_ok)
  1142. {
  1143.   CClass *ptr;            /* pointer to class data in buffer */
  1144.   GDataClass *cl;        /* unmodified class data */
  1145.   GLYPH g;
  1146.   int i;
  1147.  
  1148.   for (i = 0; i < number; i++)
  1149.     {
  1150.       ptr = CGet (conn, CClass);
  1151.       g = read_energize_image_data (conn, binfo);
  1152.       cl = get_class (ptr->classId, binfo);
  1153.  
  1154.       if (!cl)
  1155.     cl = alloc_GDataclass (ptr->classId, binfo);
  1156.       else if (!modify_ok)
  1157.     message("Attempt to create class with existing Id %8x", ptr->classId);
  1158.  
  1159.       if (ignore_kernel) continue;
  1160.  
  1161.       /* if it did exist, we just clobber it */
  1162.       if (cl->flags != ptr->flags)
  1163.     {
  1164.       cl->flags = ptr->flags;
  1165.       BUF_FACECHANGE (XBUFFER (binfo->emacs_buffer))++;
  1166.     }
  1167.       if (cl->glyph != g)
  1168.     {
  1169.       cl->glyph = g;
  1170.       BUF_FACECHANGE (XBUFFER (binfo->emacs_buffer))++;
  1171.     }
  1172.     }
  1173. }
  1174.  
  1175. /* Parse GenericData form the connection buffer.  Defines them for the buffer
  1176.  * given as argument */
  1177. static void
  1178. read_energize_generic_data (Connection *conn, unsigned int number,
  1179.          BufferInfo *binfo, unsigned int modify_ok)
  1180. {
  1181.   CGeneric *ptr;
  1182.   GenericData *gen;
  1183.   GDataClass *cl;
  1184.   GLYPH g;
  1185.   int i;
  1186.  
  1187.   for (i = 0; i < number; i++)
  1188.     {
  1189.       ptr = CGet (conn, CGeneric);
  1190.       g = read_energize_image_data (conn, binfo);
  1191.       gen = get_generic (ptr->genericId, binfo);
  1192.       cl = get_class (ptr->classId, binfo);
  1193.  
  1194.       if (!gen)
  1195.     {
  1196.       /* create generic if it didn't already exist */
  1197.  
  1198.       if (!cl)
  1199.         {
  1200.           message ("Attempt to create generic %8x with undefined class %8x",
  1201.              ptr->genericId, ptr->classId);
  1202.           continue;
  1203.         }
  1204.  
  1205.       gen = alloc_GenericData (ptr->genericId, cl, binfo);
  1206.       gen->glyph = g;
  1207.       if (ptr->flags != 0xff) gen->flags = ptr->flags;
  1208.       gen->attribute = ptr->attribute;
  1209.     }
  1210.       else if (!modify_ok)
  1211.     message("Attempt to create generic with existing id %8x",
  1212.           ptr->genericId);
  1213.       else{
  1214.     /* modify the generic */
  1215.     int modified = 0;
  1216.     if (cl != gen->cl)
  1217.       {
  1218.         modified = 1;
  1219.         gen->cl = cl;
  1220.       }
  1221.     if (gen->glyph != g)
  1222.       {
  1223.         modified = 1;
  1224.         gen->glyph = g;
  1225.       }
  1226.     if (ptr->flags != 0xff)
  1227.       {
  1228.         modified = 1;
  1229.         gen->flags = ptr->flags;
  1230.       }
  1231.     if (gen->attribute != ptr->attribute)
  1232.       {
  1233.         modified = 1;
  1234.         gen->attribute = ptr->attribute;
  1235.       }
  1236.     if (modified)
  1237.       BUF_FACECHANGE (XBUFFER (binfo->emacs_buffer))++;
  1238.       }
  1239.     }
  1240. }
  1241.  
  1242.  
  1243. static void
  1244. insert_one_extent (CExtent* ptr, BufferInfo* binfo, int modify_ok)
  1245. {
  1246.   Energize_Extent_Data *ext;
  1247.   GenericData *gen;
  1248.   Bufpos extent_start;
  1249.   Bufpos extent_end;
  1250.   int set_endpoints_p = 1;
  1251.   int created_ext_data = 0;
  1252.   Lisp_Object buffer = binfo->emacs_buffer;
  1253.  
  1254.   ext = get_extent_data (ptr->extentId, binfo);
  1255.  
  1256.   if (!ext)
  1257.     {
  1258.       ext = (Energize_Extent_Data *) xmalloc (sizeof (Energize_Extent_Data));
  1259.       created_ext_data = 1;
  1260.       ext->seal = EXTENT_SEAL;
  1261.       ext->id = ptr->extentId;
  1262.       ext->extentType = -1;
  1263.       ext->extent = Qnil;    /* not a normal value: set before we return */
  1264.       ext->start_pixmap = 0;
  1265.       ext->end_pixmap = 0;
  1266.       ext->warn_modify = 0;
  1267.       put_extent_data (ext->id, binfo, ext);
  1268.     }
  1269.   else if (!modify_ok)
  1270.     message ("Creating extent with existing id %8x", ptr->extentId);
  1271.  
  1272.   ext->extentType = ptr->extentType;
  1273.  
  1274.   switch (ptr->extentType)
  1275.     {
  1276.     case CEAttribute:
  1277.       ext->u.attr.attrValue = ptr->data;
  1278.       break;
  1279.  
  1280.     case CEAbbreviation:
  1281.       ext->u.abbrev.isOpened = ptr->data;
  1282.       break;
  1283.  
  1284.     case CEWriteProtect:
  1285.       break;
  1286.  
  1287.     case CEGeneric:
  1288.       gen = get_generic (ptr->data, binfo);
  1289.       if (!gen)
  1290.     {
  1291.       message ("NewExtents: Nonexistent generic data %8x", ptr->data);
  1292.       return;
  1293.     }
  1294.       ext->u.generic.gData = gen;
  1295.       break;
  1296.  
  1297.     default:
  1298.       message ("Unknown extent type %d", ptr->extentType);
  1299.       break;
  1300.     }
  1301.  
  1302.   /* instruct redisplay to recompute the frame */
  1303.   BUF_FACECHANGE (XBUFFER (binfo->emacs_buffer))++;
  1304.  
  1305.   /* ptr->startPosition == ptr->endPosition == ~0 means to not change
  1306.    * the extent endpoints */
  1307.   if (ptr->startPosition == ~0 && ptr->endPosition == ~0)
  1308.     {
  1309.       set_endpoints_p = 0;
  1310.       extent_start = ~0;
  1311.       extent_end = ~0;
  1312.     }
  1313.   else
  1314.     {
  1315.       struct buffer *b = XBUFFER (buffer);
  1316.       extent_start = BufposForEnergizePos (ptr->startPosition, binfo);
  1317.       extent_end = BufposForEnergizePos (ptr->endPosition, binfo);
  1318.  
  1319.       /* We have to be careful to create the extents with endpoints
  1320.      which are in the buffer.
  1321.  
  1322.      Under certain obscure conditions involving changes made outside
  1323.      of Emacs (bug 19983), the server and the editor can have different
  1324.      ideas about where the extents are, so these numbers can be off
  1325.      temporarily (during the window between read_energize_extent_data
  1326.      and Qenergize_auto_revert_buffer in read_energize_buffer_data
  1327.      from ModifyBufferRType).
  1328.        */
  1329.  
  1330.       /* Don't allow 0-length extents, as they tend to disappear. */
  1331.       if (extent_start >= extent_end)
  1332.     extent_end = extent_start + 1;
  1333.  
  1334.       /* Don't let them outside the buffer (even if we grew them). */
  1335.       if (extent_start >= BUF_Z (b))  extent_start = BUF_Z (b) - 1;
  1336.       if (extent_end   >= BUF_Z (b))  extent_end   = BUF_Z (b) - 1;
  1337.       if (extent_start < BUF_BEG (b)) extent_start = BUF_BEG (b);
  1338.       if (extent_end   < BUF_BEG (b)) extent_end   = BUF_BEG (b);
  1339.  
  1340.       /* If they're 0-length again, then the extent must be at point-max.
  1341.      In that case, extent it backward (if possible) instead of forward.
  1342.        */
  1343.       if (extent_start >= extent_end
  1344.       && BUF_BEG (b) != BUF_Z (b))
  1345.     extent_start = extent_end - 1;
  1346.     }
  1347.  
  1348.   /* no zero width extent */
  1349.   if (set_endpoints_p && extent_start == extent_end)
  1350.     extent_end += 1;
  1351.  
  1352.   /* Now create the extent for the extent-data.  There is a 1:1 mapping between
  1353.      these, and an extent-data points at an extent (and that extent points
  1354.      back) until energize tells us to delete the extent.  This is the only
  1355.      function in which ext->extent is ever not an extent. */
  1356.   if (created_ext_data)
  1357.     {
  1358.       ext->extent = Fmake_extent (make_number (extent_start),
  1359.                   make_number (extent_end), buffer);
  1360.       set_energize_extent_data (XEXTENT (ext->extent), ext);
  1361.       restore_energize_extent_state (XEXTENT (ext->extent));
  1362.     }
  1363.   else
  1364.     {
  1365.       if (!EQ (buffer, extent_buffer (XEXTENT (ext->extent))))
  1366.     signal_simple_error_2 ("extent not part of buffer", ext->extent,
  1367.                    buffer);
  1368.  
  1369.       if (set_endpoints_p)
  1370.     Fset_extent_endpoints (ext->extent, make_number (extent_start),
  1371.                    make_number (extent_end));
  1372.       restore_energize_extent_state (XEXTENT (ext->extent));
  1373.     }
  1374.  
  1375.   if (energize_extent_data (XEXTENT (ext->extent)) != ext)
  1376.     abort ();
  1377.  
  1378.   extent_duplicable_p (XEXTENT (ext->extent)) = 1;
  1379.   extent_unique_p (XEXTENT (ext->extent)) = 1;
  1380. }
  1381.  
  1382.  
  1383. /* Parse GenericData from the connection buffer.  Defines them for the buffer
  1384.  * given as argument.  Creates the Emacs extents while parsing.
  1385.  * Energize sends the extents ordered by increasing starting position.
  1386.  I don't think the following is true any more:
  1387.  * Emacs is __much__ faster at inserting them in decreasing starting position
  1388.  * also for overlaps to work correctly the outmost extents have to be
  1389.  * inserted first.  This is what the recursive function is trying to do.
  1390.  */
  1391. static void
  1392. read_energize_extent_data (Connection *conn, unsigned int number,
  1393.                BufferInfo *binfo, unsigned int modify_ok,
  1394.                int extent_offset)
  1395. {
  1396.   CExtent* all_extents;
  1397.   int i;
  1398.  
  1399.   /* Gets the extents from the connection */
  1400.   all_extents = CGetN (conn, CExtent, number);
  1401.  
  1402.   /* adjusts the endpoints with the offset */
  1403.   for (i = 0; i < number; i++)
  1404.     {
  1405.       if (all_extents [i].startPosition != ~0)
  1406.     all_extents [i].startPosition += extent_offset;
  1407.       if (all_extents [i].endPosition != ~0)
  1408.     all_extents [i].endPosition += extent_offset;
  1409.     }
  1410.  
  1411.   /* inserts them all */
  1412.   for (i = number - 1; i >= 0; i--)
  1413.     {
  1414.       insert_one_extent (all_extents + i, binfo, modify_ok);
  1415.     }
  1416. }
  1417.  
  1418. /* Parses a CBuffer in the connection stream. If (delete_from != delete_to)
  1419.    all characters in this range must be deleted.
  1420.    */
  1421.  
  1422. static int
  1423. string_buffer_compare (char *string, int string_len,
  1424.                struct buffer *buf, Bufpos bufpos)
  1425. {
  1426.   /* !!#### needs to be rewritten for Mule */
  1427.   Bufpos first_section_end = BUF_CEILING_OF (buf, bufpos);
  1428.  
  1429.   /* degenerate case, which we consider to be "true" */
  1430.   if (string_len == 0) return 0;
  1431.  
  1432.   /* string won't fit in the buffer, so comparison fails */
  1433.   if (BUF_Z (buf) < (bufpos + string_len)) return -1;
  1434.  
  1435.   /* bad starting position, so comparison fails */
  1436.   if (bufpos < BUF_BEG (buf)) return -1;
  1437.  
  1438.   {
  1439.     char *first_section_chars = (char *) BUF_BYTE_ADDRESS (buf, bufpos);
  1440.     int comp = strncmp (string, first_section_chars,
  1441.             first_section_end - bufpos);
  1442.     
  1443.     if (comp) return comp;
  1444.   }
  1445.  
  1446.   if (first_section_end < BUF_ZV (buf))
  1447.     /* there is a second section */
  1448.     {
  1449.       char *second_section_chars =
  1450.     (char *) BUF_BYTE_ADDRESS (buf, first_section_end);
  1451.       int comp = strncmp (string + (first_section_end - bufpos),
  1452.               second_section_chars,
  1453.               BUF_ZV (buf) - first_section_end);
  1454.  
  1455.       if (comp) return comp;
  1456.     }
  1457.  
  1458.   return 0;
  1459. }
  1460.  
  1461. /* called by unwind protect, from within ParseBuffer and HandleRemoveExtents */
  1462. static Lisp_Object
  1463. restore_buffer_state (Lisp_Object state_cons)
  1464. {
  1465.   BufferInfo *binfo;
  1466.   Lisp_Object bufferId_obj = Fcar (state_cons);
  1467.   unsigned int bufferId = (unsigned int) get_opaque_ptr (bufferId_obj);
  1468.   Lisp_Object buffer_modified_state = Fcar (Fcdr (state_cons));
  1469.   Lisp_Object clear_undo_list = Fcdr (Fcdr (state_cons));
  1470.  
  1471.   if (bufferId != 0)
  1472.     {
  1473.       if (energize_connection
  1474.       && (binfo = get_buffer_info_for_id (bufferId, energize_connection))
  1475.       && !NILP (binfo->emacs_buffer))
  1476.     {
  1477.       /* Always ignore what Energize tells us about the buffer read-only
  1478.          state.  For files Emacs knows better and for non-file buffers
  1479.          Emacs is hacking the read-only state anyway so let it be. */
  1480.       XBUFFER (binfo->emacs_buffer)->read_only = buffer_modified_state;
  1481.       if (!NILP (clear_undo_list))
  1482.         XBUFFER (binfo->emacs_buffer)->undo_list = Qnil;
  1483.     }
  1484.     }
  1485.   else
  1486.     /* this is just temporary */
  1487.     message ("Bad bufferId cons cell!");
  1488.   return Qnil;
  1489. }
  1490.  
  1491. /* #### this shit should be using generate-new-buffer */
  1492. static void
  1493. rename_the_buffer (Lisp_Object new_name)
  1494. {
  1495.   int count = 0;
  1496.   char number [8];
  1497.   struct gcpro gcpro1;
  1498.  
  1499.   Lisp_Object name = new_name;
  1500.   GCPRO1 (name);
  1501.   while (!NILP (Fget_buffer (name)))
  1502.     {
  1503.       sprintf (number, "<%d>", ++count);
  1504.       name = concat2 (new_name, build_string (number));
  1505.     }
  1506.   Frename_buffer (name, Qnil);
  1507.   UNGCPRO;
  1508. }
  1509.  
  1510. static int
  1511. destroy_if_energize_extent (EXTENT e, void* arg)
  1512. {
  1513.   struct Energize_Extent_Data *ext = energize_extent_data (e);
  1514.   if (ext)
  1515.     {
  1516.       Lisp_Object extent;
  1517.       Lisp_Object buffer;
  1518.       BufferInfo *binfo = 0;
  1519.       XSETEXTENT (extent, e);
  1520.       buffer = extent_buffer (XEXTENT (extent));
  1521.       Fdelete_extent (extent);
  1522.       if (BUFFERP (buffer))
  1523.     binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
  1524.       if (binfo)
  1525.     free_Energize_Extent_Data (ext, binfo, OFT_GC);
  1526.       else
  1527.     {
  1528.       /* #### partly duplicated in free_Energize_Extent_Data() */
  1529.       set_energize_extent_data (e, 0);
  1530.       ext->extent = Qnil;
  1531.     }
  1532.     }
  1533.   return 0;
  1534. }
  1535.  
  1536. static void
  1537. destroy_all_energize_extents (struct buffer *buf)
  1538. {
  1539.   map_extents (BUF_BEG (buf), BUF_Z (buf), destroy_if_energize_extent,
  1540.            NULL, make_buffer (buf), 0,
  1541.            ME_END_CLOSED | ME_MIGHT_MODIFY_EXTENTS);
  1542. }
  1543.  
  1544. static Lisp_Object
  1545. restore_inside_parse_buffer (Lisp_Object val)
  1546. {
  1547.   inside_parse_buffer = XINT (val);
  1548.   return (val);
  1549. }
  1550.  
  1551. static void
  1552. hack_window_point (Lisp_Object window,
  1553.            Lisp_Object old_point,
  1554.            Lisp_Object old_start,
  1555.            int keep_start_p,
  1556.            BufferInfo *binfo)
  1557.      /* If we've reverted a buffer, sometimes we want to make sure that
  1558.     the window-point doesn't move. */
  1559. {
  1560.   if (NILP (window))
  1561.     return;
  1562.  
  1563.   Fset_marker (XWINDOW (window)->pointm, old_point, binfo->emacs_buffer);
  1564.   if (NILP (binfo->output_mark) && keep_start_p)
  1565.     {
  1566.       Fset_marker (XWINDOW (window)->start, old_start, binfo->emacs_buffer);
  1567.       XWINDOW (window)->force_start = 1;
  1568.     }
  1569. }
  1570.  
  1571. static void
  1572. read_energize_buffer_data (Connection *conn, CBuffer *cbu, Editor *editor,
  1573.                EnergizePos delete_from, EnergizePos delete_to,
  1574.                Window win, int relative_p)
  1575. {
  1576.   char *name;
  1577.   ReqLen name_len;
  1578.   char *pathname_str;
  1579.   ReqLen pathname_len;
  1580.   char *buffer_class_str;
  1581.   ReqLen buffer_class_len;
  1582.   Lisp_Object pathname = Qnil;
  1583.   Lisp_Object pathname_directory = Qnil;
  1584.   Lisp_Object buffer_name = Qnil;
  1585.   Lisp_Object filename = Qnil;
  1586. #if 1
  1587.   Lisp_Object display_window = Qnil;
  1588. #endif
  1589.   BufferInfo *binfo;
  1590.   int modifying_p = 0;
  1591.   Bufpos previous_point;
  1592.   Bufpos from;
  1593.   Bufpos to;
  1594. #if 1
  1595.   Bufpos display_start = 1;
  1596. #endif
  1597.   char *text;
  1598.   ReqLen text_len;
  1599.   int get_chars_from_file = 0;
  1600.   Lisp_Object modified_buffer_flag;
  1601.   int speccount = specpdl_depth ();
  1602.   int extent_offset;
  1603.   Lisp_Object restore_buffer_state_cons;
  1604.   int should_keep_window_start = 1;
  1605.   int no_text_deleted = 0;
  1606.  
  1607.   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
  1608.  
  1609.   /* For some reason calling the GC before parsing the buffer data
  1610.      makes a better usage of memory and emacs leaks less when 
  1611.      creating/deleting LE browser buffers.  
  1612.      However you don't want to call GC all the tiem so we only do it if the request
  1613.      will create more than a given number of extents. */
  1614.   if (cbu->nExtent > energize_extent_gc_threshold)
  1615.     garbage_collect_1 ();
  1616.  
  1617.   record_unwind_protect (save_restriction_restore, save_restriction_save ());
  1618.  
  1619.   Fwiden (Fcurrent_buffer ());
  1620.  
  1621.   GCPRO4 (buffer_name, pathname, pathname_directory, filename);
  1622.  
  1623.   name = CGetVstring (conn, &name_len);
  1624.  
  1625.   /* read the pathname and buffer-class -- Editor Protocol > 0 */
  1626.   pathname_str = CGetVstring (conn, &pathname_len);
  1627.   buffer_class_str = CGetVstring (conn, &buffer_class_len);
  1628.  
  1629.   if (name_len)
  1630.     buffer_name = build_string (name);
  1631.   if (pathname_len)
  1632.     pathname = build_string (pathname_str);
  1633.  
  1634.   /* set up pathname_directory */
  1635.   if (!NILP (pathname))
  1636.     {
  1637.       if (NILP (Ffile_directory_p (pathname)))
  1638.     pathname_directory = Ffile_name_directory (pathname);
  1639.       else
  1640.     pathname_directory = pathname;
  1641.     }
  1642.  
  1643.   /* make sure that pathname_directory ends with a '/', if it exists */
  1644.   if (!NILP (pathname_directory))
  1645.     {
  1646.       Bufbyte *str = string_data (XSTRING (pathname_directory));
  1647.       Bytecount size = string_length (XSTRING (pathname_directory));
  1648.       if (str[size - 1] != '/')
  1649.     {
  1650.       Lisp_Object tmp = make_string (str, size + 1);
  1651.       set_string_byte (XSTRING (tmp), size, '/');
  1652.       pathname_directory = tmp;
  1653.     }
  1654.     }
  1655.  
  1656.  
  1657.   /* get or create the BufferInfo */
  1658.   if (binfo = get_buffer_info_for_id (cbu->bufferId, editor))
  1659.     modifying_p = 1;
  1660.   else
  1661.     {
  1662.       if (NILP (buffer_name))
  1663.     {
  1664.       char *dummy = "*Unnamed " IDENTITY_CRISIS " Buffer*";
  1665.       buffer_name = build_string (dummy);
  1666.     }
  1667.       /* create new buffer */
  1668.       binfo = alloc_BufferInfo (cbu->bufferId, buffer_name, pathname,
  1669.                 buffer_class_str, editor, win,
  1670.                 cbu->nExtent + cbu->nClass + cbu->nGeneric);
  1671.       XBUFFER (binfo->emacs_buffer)->read_only =
  1672.     cbu->flags == CBReadOnly ? Qt : Qnil;
  1673.     }
  1674.  
  1675.   /* remember where we were in which buffer before we change things */
  1676.   if (current_buffer != XBUFFER (binfo->emacs_buffer))
  1677.     {
  1678.       record_unwind_protect (save_excursion_restore, save_excursion_save ());
  1679.       Fset_buffer (binfo->emacs_buffer);
  1680.     }
  1681.  
  1682.   /* set default-directory */
  1683.   if (!NILP (pathname_directory))
  1684.     {
  1685.       if (!NILP (Ffile_directory_p (pathname_directory))
  1686.       && !NILP (Ffile_executable_p (pathname_directory)))
  1687.     Fset (Qdefault_directory, pathname_directory);
  1688.       /* Never set this to nil, that loses badly. */
  1689. /*      else
  1690.     Fset (Qdefault_directory, Qnil); */
  1691.     }
  1692.  
  1693.   /* set file name unless it's a directory */
  1694.   if (!NILP (pathname) && NILP (Ffile_directory_p (pathname)))
  1695.     {
  1696.       filename = Fexpand_file_name (pathname, Qnil);
  1697.       Fset (Qbuffer_file_name, filename);
  1698.     }
  1699.  
  1700.   /* set buffer name */
  1701.   if (!NILP (buffer_name))
  1702.     {
  1703.       if (modifying_p
  1704.       && strcmp ((char*)string_data (XSTRING (buffer_name)),
  1705.              (char*)
  1706.              string_data (XSTRING (XBUFFER (binfo->emacs_buffer)->name))))
  1707.     rename_the_buffer (buffer_name);
  1708.     }
  1709.  
  1710.   if (modifying_p)
  1711.     {
  1712.       call1 (Vrun_hooks, Venergize_kernel_modification_hook);
  1713.       /* Make sure buffer is current after the hook */
  1714.       Fset_buffer (binfo->emacs_buffer);
  1715.     }
  1716.  
  1717.   modified_buffer_flag = Fbuffer_modified_p (binfo->emacs_buffer);
  1718.  
  1719.   /* enables buffer edits */
  1720.   restore_buffer_state_cons =
  1721.     Fcons (make_opaque_ptr ((void *) cbu->bufferId),
  1722.        Fcons (XBUFFER (binfo->emacs_buffer)->read_only, Qt));
  1723.   record_unwind_protect (restore_buffer_state, restore_buffer_state_cons);
  1724.   XBUFFER (binfo->emacs_buffer)->read_only = Qnil;
  1725.  
  1726.   /* any changes here should take place "underneath" these hooks, I think */
  1727.   specbind (Qenergize_buffer_modified_hook, Qnil);
  1728.   specbind (Qfirst_change_hook, Qnil);
  1729.   specbind (Qbefore_change_functions, Qnil);
  1730.   specbind (Qbefore_change_function, Qnil); /* #### */
  1731.   /* As energize does not use the after-change-function it's not useful to
  1732.      bind it to NIL */
  1733.   /* specbind (Qafter_change_functions, Qnil); */
  1734.   /* specbind (Qafter_change_function, Qnil); #### */
  1735.   record_unwind_protect (restore_inside_parse_buffer,
  1736.              make_number (inside_parse_buffer));
  1737.   inside_parse_buffer = 1;
  1738.   specbind (Qbuffer_undo_list, Qt);
  1739.  
  1740.   XBUFFER (binfo->emacs_buffer)->undo_list = Qt;
  1741.  
  1742.   /* BufposForEnergizePos uses the current-buffer */
  1743.   from = BufposForEnergizePos (delete_from, binfo);
  1744.   to = BufposForEnergizePos (delete_to, binfo);
  1745.  
  1746.   /* See if we should get the characters from the file directly.
  1747.      Only protocol 0.10+ will do this.
  1748.    */
  1749. #ifdef ENERGIZE_V2_HEADERS
  1750.   get_chars_from_file = 0;
  1751. #else
  1752.   if (cbu->flags != 0xff)
  1753.     get_chars_from_file = cbu->flags &  CBFileYourself;
  1754.   else
  1755.     get_chars_from_file = binfo->flags &  CBFileYourself;
  1756. #endif
  1757.   
  1758.   /* Even when we get the chars from a file there is an empty text string */
  1759.   if (get_chars_from_file)
  1760.     {
  1761.       text = CGetVstring (conn, &text_len);
  1762.       text = NULL;
  1763.       text_len = 0;
  1764.     }
  1765.   else
  1766.     {
  1767.       text = CGetVstring (conn, &text_len);
  1768.     }
  1769.   
  1770.   /* updates the visited file modtime */
  1771.   if (modifying_p && (from != to || text_len)
  1772.       /* but only when we do not read the file ourselves */
  1773.       && !get_chars_from_file)
  1774.     Fset_buffer_modtime (binfo->emacs_buffer, Qnil);
  1775.  
  1776.   if (!modifying_p)
  1777.     {
  1778.       /* clears the buffer in case we re-use a non-energize buffer */
  1779.       previous_point = 1;
  1780.       Fset_buffer (binfo->emacs_buffer);
  1781.       buffer_delete_range (current_buffer, BUF_BEG (current_buffer), BUF_Z (current_buffer), 0);
  1782.     }
  1783.   else
  1784.     {
  1785. #if 1
  1786.       display_window = Fget_buffer_window (binfo->emacs_buffer, Qnil, Qnil);
  1787. #endif
  1788.       previous_point = BUF_PT (current_buffer);
  1789.  
  1790. #if 1
  1791.       if (!NILP (display_window))
  1792.     display_start =
  1793.       XINT (Fmarker_position (XWINDOW (display_window)->start));
  1794. #endif
  1795.  
  1796.       if (from != to)
  1797.     {
  1798.       struct buffer *buf = XBUFFER (binfo->emacs_buffer);
  1799.  
  1800.       Fset_buffer (binfo->emacs_buffer);
  1801.       Fwiden (Fcurrent_buffer ());
  1802.       if (!NILP (binfo->output_mark)
  1803.           && marker_position (binfo->output_mark) >= from)
  1804.         Fset_marker (binfo->output_mark, make_number (from),
  1805.              binfo->emacs_buffer);
  1806.       if (((to - from) == text_len) && !get_chars_from_file &&
  1807.           !string_buffer_compare (text, text_len, buf, from))
  1808.         /* the new text is the same as the old text, don't clear
  1809.            the undo list*/
  1810.         {
  1811.           Fsetcdr (Fcdr (restore_buffer_state_cons), Qnil);
  1812.           no_text_deleted = 1;
  1813.           destroy_all_energize_extents (buf);
  1814.         }
  1815.       else
  1816.         {
  1817.           /* Do not keep window start if we actually delete text */
  1818.           should_keep_window_start = 0;
  1819.           Fset_buffer (binfo->emacs_buffer);
  1820.           destroy_all_energize_extents (buf);
  1821.           if (!get_chars_from_file)
  1822.         buffer_delete_range (current_buffer, from, to, 0);
  1823.         }
  1824.  
  1825.       /* Do not clear the undo list if getting the chars from the file */
  1826.       if (get_chars_from_file)
  1827.         Fsetcdr (Fcdr (restore_buffer_state_cons), Qnil);
  1828.     }
  1829.       else if (!text_len && !get_chars_from_file)
  1830.     /* if there is no text and we didn't delete anything,
  1831.        don't clear the undo_list slot */
  1832.     Fsetcdr (Fcdr (restore_buffer_state_cons), Qnil);
  1833.  
  1834.     }
  1835.  
  1836.   /* buffer type */
  1837.   if (cbu->flags != 0xff && cbu->flags != binfo->flags)
  1838.     {
  1839.       if (!modifying_p)
  1840.     {
  1841.       if (cbu->flags == CBUserInput)
  1842.         {
  1843.           Lisp_Object buffer_local_variable_name =
  1844.         Qenergize_user_input_buffer_mark;
  1845.           binfo->output_mark = Fmake_marker ();
  1846.           Fset_marker (binfo->output_mark, make_number (1),
  1847.                binfo->emacs_buffer);
  1848.           /* make sure that this guy doesn't get GC'd out from under us */
  1849.           Fmake_local_variable (buffer_local_variable_name);
  1850.           Fput (buffer_local_variable_name, Qpermanent_local, Qt);
  1851.           Fset (buffer_local_variable_name, binfo->output_mark);
  1852.           /* Make sure buffer is current after the hook */
  1853.           Fset_buffer (binfo->emacs_buffer);
  1854.         }
  1855.     }
  1856.       binfo->flags = cbu->flags;
  1857.     }
  1858.  
  1859.   if (get_chars_from_file && text_len != 0)
  1860.     /* I think this is always true, but let's make sure - jwz */
  1861.     abort ();
  1862.  
  1863.   if (text_len)
  1864.     {
  1865.       if (!NILP (binfo->output_mark))
  1866.     {
  1867.       Fset_buffer (binfo->emacs_buffer);
  1868.       if (XMARKER (binfo->output_mark)->buffer)
  1869.         Fgoto_char (binfo->output_mark, Fcurrent_buffer ());
  1870.       else
  1871.         /* This should not happen */
  1872.         Fgoto_char (make_number (BUF_ZV (XBUFFER (binfo->emacs_buffer))),
  1873.             Fcurrent_buffer ());
  1874.  
  1875.       if (BUF_PT (current_buffer) <= previous_point)
  1876.         {
  1877. #if 1
  1878.           display_start += text_len;
  1879. #endif
  1880.           previous_point += text_len;
  1881.         }
  1882.       buffer_insert_raw_string (current_buffer, text, text_len);
  1883.       Fset_marker (binfo->output_mark, make_number (BUF_PT (current_buffer)),
  1884.                binfo->emacs_buffer);
  1885.     }
  1886.       else if (modifying_p)
  1887.     {
  1888.       Fgoto_char (make_number (from), Fcurrent_buffer ());
  1889.       if (!no_text_deleted)
  1890.         buffer_insert_raw_string (current_buffer, text, text_len);
  1891.     }
  1892.       else
  1893.     buffer_insert_raw_string (current_buffer, text, text_len);
  1894.  
  1895.       previous_point = XINT (Fgoto_char (make_number (previous_point)),
  1896.                  Fcurrent_buffer ());
  1897.     }
  1898.   else if (get_chars_from_file && !modifying_p)
  1899.     {
  1900.       /* !modifying_p means the buffer is being created - read the text
  1901.      from the file. */
  1902.       Finsert_file_contents_internal (Fbuffer_file_name (binfo->emacs_buffer),
  1903.                       Qt, Qnil, Qnil, Qnil));
  1904.     }
  1905.  
  1906.   if (!relative_p)
  1907.     extent_offset = 0;
  1908.   else if (!NILP (binfo->output_mark))
  1909.     extent_offset = EnergizePosForBufpos (XINT (Fmarker_position
  1910.                              (binfo->output_mark)),
  1911.                        binfo);
  1912.   else
  1913.     extent_offset = EnergizePosForBufpos (BUF_Z(XBUFFER(binfo->emacs_buffer)),
  1914.                        binfo);
  1915.   
  1916. #if 1
  1917.   if (text_len || !text)
  1918.     hack_window_point (display_window,
  1919.                make_number (previous_point),
  1920.                make_number (display_start),
  1921.                should_keep_window_start,
  1922.                binfo);
  1923. #endif
  1924.  
  1925.  
  1926.   /* Classes, generics and extents */
  1927.   /* make sure that we have enough room in the hash table */
  1928.   expand_hashtable (binfo->id_to_object,
  1929.             cbu->nClass + cbu->nGeneric + cbu->nExtent);
  1930.   read_energize_class_data (conn, cbu->nClass, binfo, modifying_p);
  1931.   read_energize_generic_data (conn, cbu->nGeneric, binfo, modifying_p);
  1932.   read_energize_extent_data (conn, cbu->nExtent, binfo, modifying_p, extent_offset);
  1933.  
  1934.   /* Restore the modified bit */
  1935.   Fset_buffer_modified_p (modified_buffer_flag, binfo->emacs_buffer);
  1936.  
  1937.   if (get_chars_from_file && modifying_p)
  1938.     {
  1939.       /* modifying_p means the buffer already exists and the extents are
  1940.      being re-written.  It may be that the file has changed on disk,
  1941.      and the extents no longer correspond to the text in the buffer,
  1942.      which would be bad.  So, check the file on disk, and if it has
  1943.      changed, offer to revert.
  1944.  
  1945.      As this runs lisp code which may prompt the user, and consequently
  1946.      may accept process output, be careful to do this after we have
  1947.      finished reading the current request from the Energize connection.
  1948.        */
  1949.      if (NILP (Fverify_visited_file_modtime (binfo->emacs_buffer)))
  1950.        {
  1951.      call1 (Qenergize_auto_revert_buffer, binfo->emacs_buffer);
  1952.      hack_window_point (display_window,
  1953.                 make_number (previous_point),
  1954.                 make_number (display_start),
  1955.                 1,
  1956.                 binfo);
  1957.        }
  1958.    }
  1959.  
  1960.  
  1961.   /* restore modified hooks and globals, and return the previous buffer */
  1962.   UNGCPRO;
  1963.   unbind_to (speccount, Qnil);
  1964. }
  1965.  
  1966.  
  1967. static void
  1968. cleanly_destroy_all_widgets (int count, LWLIB_ID *ids)
  1969. {
  1970.   /* This just calls lw_destroy_all_widgets, but is careful to make sure that
  1971.      this doesn't cause the frames to shrink.  If one deletes psheets
  1972.      (children of the "control" area of the MainWindow) without first
  1973.      unmanaging the MainWindow, the frame resizes.  So first unmanage all
  1974.      the MainWindows of all applicable frames, then remanage them.  This is
  1975.      nasty, but...
  1976.    */
  1977.   Lisp_Object tail;
  1978.   struct frame *f;
  1979.   int i, j;
  1980.  
  1981.   if (count == 0) return;
  1982.   for (tail = DEVICE_FRAME_LIST (get_x_device(Qnil)); 
  1983.        CONSP (tail); tail = XCDR (tail))
  1984.     {
  1985.       Lisp_Object frame = XCAR (tail);
  1986.       if (!FRAMEP (frame))
  1987.     continue;
  1988.       f = XFRAME (frame);
  1989.       if (!FRAME_IS_X (f))
  1990.     continue;
  1991.       /* Optimization: only unmanage the MainWindow if this frame is
  1992.      displaying one of the psheets in question.  (Special casing
  1993.      the debugger panel as usual...)
  1994.        */
  1995.       for (i = 0; i < count; i++)
  1996.     if (ids [i] == debuggerpanel_sheet)
  1997.       {
  1998.         XtUnmanageChild (FRAME_X_CONTAINER_WIDGET (f));
  1999.         goto next_frame;
  2000.       }
  2001.     else
  2002.       for (j = 0; j < FRAME_X_CURRENT_PSHEET_COUNT (f); j++)
  2003.         if (ids [i] == FRAME_X_CURRENT_PSHEETS (f) [j])
  2004.           {
  2005.         XtUnmanageChild (FRAME_X_CONTAINER_WIDGET (f));
  2006.         goto next_frame;
  2007.           }
  2008.     next_frame: ;
  2009.     }
  2010.  
  2011.   for (i = 0; i < count; i++)
  2012.     {
  2013.       lw_destroy_all_widgets (ids [i]);
  2014.       if (ids [i] == debuggerpanel_sheet)
  2015.     {
  2016.       debuggerpanel_sheet = 0;
  2017.       desired_debuggerpanel_exposed_p = 0;
  2018.     }
  2019.     }
  2020.  
  2021.   for (tail = DEVICE_FRAME_LIST (get_x_device(Qnil)); CONSP (tail); tail = XCDR (tail))
  2022.     {
  2023.       Lisp_Object frame = XCAR (tail);
  2024.       if (!FRAMEP (frame))
  2025.     continue;
  2026.       f = XFRAME (frame);
  2027.       if (!FRAME_IS_X (f))
  2028.     continue;
  2029.       XtManageChild (FRAME_X_CONTAINER_WIDGET (f));
  2030.     }
  2031. }
  2032.  
  2033.  
  2034. /* kill an Energize buffer */
  2035. static void
  2036. forget_buffer (BufferInfo *binfo)
  2037. {
  2038.   int i;
  2039.   Lisp_Object buffer = binfo->emacs_buffer;
  2040.  
  2041.   remove_buffer_info (binfo->id, buffer, binfo->editor);
  2042.   Venergize_buffers_list = Fdelq (buffer, Venergize_buffers_list);
  2043.  
  2044.   /* if there was an associated frame */
  2045.   if (!NILP (binfo->frame))
  2046.     Fdelete_frame (binfo->frame);
  2047.  
  2048.   if (binfo->n_p_sheets > 0)
  2049.     {
  2050.       /* Also delete the dialog boxes associated with the buffer. */
  2051.       cleanly_destroy_all_widgets (binfo->n_p_sheets,
  2052.                    (LWLIB_ID *) binfo->p_sheet_ids);
  2053.     }
  2054.  
  2055.   free_buffer_info (binfo);
  2056.  
  2057.   XBUFFER (buffer)->undo_list = Qnil;
  2058.   /* flush the buffer SOE before flushing the extents */
  2059.   free_buffer_cached_stack (XBUFFER (buffer));
  2060.   XBUFFER (buffer)->extents = Qnil;
  2061. }
  2062.  
  2063. /********************** Request-related utilities ************************/
  2064.  
  2065. /* outputs a single extent in the connection buffer */
  2066. static void
  2067. write_energize_extent_data (Connection *conn, Energize_Extent_Data *ext,
  2068.                 unsigned int start, unsigned int end)
  2069. {
  2070.   switch (ext->extentType)
  2071.     {
  2072.     case CEAttribute:
  2073.       CWriteExtent (conn, CEAttribute, ext->id, start, end,
  2074.             (EId)ext->u.attr.attrValue);
  2075.       break;
  2076.  
  2077.     case CEAbbreviation:
  2078.       CWriteExtent (conn, CEAbbreviation, ext->id, start, end,
  2079.             (EId)ext->u.abbrev.isOpened);
  2080.       break;
  2081.  
  2082.     case CEGeneric:
  2083.       CWriteExtent (conn, CEGeneric, ext->id, start, end, 0);
  2084.       break;
  2085.  
  2086.     case CEWriteProtect:
  2087.       CWriteExtent (conn, CEWriteProtect, ext->id, start, end, 0);
  2088.       break;
  2089.     }
  2090. }
  2091.  
  2092. /* Function called by map_extents in SaveBufferToEnergize. Outputs the
  2093.    extents for the extents corresponding to Energize objects, and
  2094.    increments the n_extents count. */
  2095.  
  2096. static int
  2097. write_energize_extent_data_mapper (EXTENT extent, void *arg)
  2098. {
  2099.   binfo_and_n_extents *bane = (binfo_and_n_extents*)arg;
  2100.   Lisp_Object extent_obj;
  2101.   Energize_Extent_Data *ext;
  2102.  
  2103.   XSETEXTENT (extent_obj, extent);
  2104.   ext = extent_to_data (extent_obj);
  2105.   if (ext)
  2106.     {
  2107.       Bufpos first = XINT (Fextent_start_position (extent_obj));
  2108.       Bufpos last = XINT (Fextent_end_position (extent_obj));
  2109.       write_energize_extent_data (bane->binfo->editor->conn, ext,
  2110.                   EnergizePosForBufpos (first, bane->binfo),
  2111.                   EnergizePosForBufpos (last, bane->binfo));
  2112.       bane->n_extents += 1;
  2113.     }
  2114.   return 0;
  2115. }
  2116.  
  2117. /* Sends a BufferSaved request to energize for binfo */
  2118. static void
  2119. write_energize_buffer_data (BufferInfo *binfo)
  2120. {
  2121.   Connection *conn = binfo->editor->conn;
  2122.   EId bufferId = binfo->id;
  2123.   CBuffer *cbu;
  2124.   CEditorRequest *req;
  2125.   struct buffer *cur_buff = current_buffer;
  2126.   int speccount = specpdl_depth ();
  2127.   Lisp_Object file_name;
  2128.  
  2129.   binfo_and_n_extents bane;
  2130.  
  2131.   /* selects the buffer as current */
  2132.   Fset_buffer (binfo->emacs_buffer);
  2133.  
  2134.   /* write header */
  2135.   cbu = CWriteBufferSavedHeader (conn);
  2136.   cbu->bufferId = bufferId;
  2137.   cbu->flags = 0;
  2138.   cbu->nClass = 0;
  2139.   cbu->nGeneric = 0;
  2140.  
  2141.   /* file name */
  2142.   file_name = current_buffer->filename;
  2143.   if (STRINGP (file_name))
  2144.     CWriteVstring0 (conn, string_data (XSTRING (file_name)));
  2145.   else
  2146.     CWriteVstring0 (conn, "");
  2147.   CWriteVstring0 (conn, "");    /* directory name */
  2148.   CWriteVstring0 (conn, "");    /* buffer name */
  2149.  
  2150.   /* write the text */
  2151. #ifndef ENERGIZE_V2_HEADERS
  2152.   if (binfo->flags & CBFileYourself)
  2153.     {
  2154.       /* Only the 0.10+ protocol will ask us to write the file directly. */
  2155.       Lisp_Object start;
  2156.       Lisp_Object end;
  2157.       XSETINT (start, BUF_BEG (current_buffer));
  2158.       XSETINT (end, BUF_Z (current_buffer));
  2159.       Fwrite_region_internal (start, end,
  2160.                   Fbuffer_file_name (binfo->emacs_buffer),
  2161.                   Qnil, Qt);
  2162.       CNeedOutputSize (conn, 9);
  2163.       CWriteVstringLen (conn, NULL, 0);
  2164.     }
  2165.   else
  2166. #endif /*  ENERGIZE_V2_HEADERS */
  2167.     {
  2168.       Lisp_Object string = make_string_from_buffer (current_buffer,
  2169.                             BUF_BEG (current_buffer),
  2170.                             BUF_Z (current_buffer));
  2171.       CNeedOutputSize (conn, string_length (XSTRING (string)) + 9);
  2172.       CWriteVstringLen (conn, string_data (XSTRING (string)),
  2173.             string_length (XSTRING (string)));
  2174.     }
  2175.  
  2176.   /* write the extents */
  2177.   bane.binfo = binfo;
  2178.   bane.n_extents = 0;
  2179.  
  2180.   /* Only write the extents when not filing ourselves */
  2181. #ifndef ENERGIZE_V2_HEADERS
  2182.   if (!(binfo->flags & CBFileYourself))
  2183. #endif
  2184.     {
  2185.       map_extents (BUF_BEG (current_buffer), BUF_Z (current_buffer),
  2186.            write_energize_extent_data_mapper, &bane,
  2187.            binfo->emacs_buffer, 0, ME_END_CLOSED);
  2188.       
  2189.     }
  2190.  
  2191.   /* update nextent in request's header */
  2192.   req = (CEditorRequest *)conn->header;
  2193.   req->buffersaved.buffer.nExtent = bane.n_extents;
  2194.   CWriteLength (conn);
  2195.   CWriteRequestBuffer (conn);
  2196.  
  2197.   /* sets the flags so that we will warn Energize about more modifications */
  2198.   binfo->modified_state = 0;
  2199.  
  2200.   /* Mark the buffer as non editable so that we will ask Energize about it
  2201.      before modifying it again */
  2202.   binfo->editable = 0;
  2203.  
  2204.   /* restores the buffer as current */
  2205.   set_buffer_internal (cur_buff);
  2206.   unbind_to (speccount, Qnil);
  2207. }
  2208.  
  2209. static unsigned long
  2210. energize_extent_data_id (Energize_Extent_Data *ext)
  2211. {
  2212.   return ext ? ext->id : 0;
  2213. }
  2214.  
  2215.  
  2216. /********************** Menu ("keywords") operations **********************/
  2217.  
  2218. static int
  2219. something_answered_p (void* arg)
  2220. {
  2221.   struct reply_wait* rw = (struct reply_wait*)arg;
  2222.   return rw->answered_p || !energize_connection || !energize_connection->conn;
  2223. }
  2224.  
  2225.  
  2226. static void
  2227. push_wait (struct reply_wait* rw)
  2228. {
  2229.   rw->next = global_reply_wait;
  2230.   global_reply_wait = rw;
  2231. }
  2232.  
  2233. static Lisp_Object
  2234. remove_wait (Lisp_Object obj)
  2235. {
  2236.   struct reply_wait* gw;
  2237.   struct reply_wait* previous;
  2238.   struct reply_wait* rw = (struct reply_wait *) get_opaque_ptr (obj);
  2239.  
  2240.   for (previous = 0, gw = global_reply_wait;
  2241.        gw != rw;
  2242.        previous = gw, gw = gw->next);
  2243.   if (previous)
  2244.     previous->next = gw->next;
  2245.   else
  2246.     global_reply_wait = gw->next;
  2247.   return Qnil;
  2248. }
  2249.  
  2250. static struct reply_wait*
  2251. find_wait_reply (int serial)
  2252. {
  2253.   struct reply_wait* gw;
  2254.   for (gw = global_reply_wait; gw && gw->serial != serial; gw = gw->next);
  2255.   return gw;
  2256. }
  2257.  
  2258.  
  2259. static int
  2260. wait_for_reply (struct reply_wait* rw)
  2261. {
  2262.   int speccount = specpdl_depth ();
  2263.   rw->answered_p = 0;
  2264.   push_wait (rw);
  2265.   record_unwind_protect (remove_wait, make_opaque_ptr (rw));
  2266.   wait_delaying_user_input (something_answered_p, rw);
  2267.   unbind_to (speccount, Qnil);
  2268.   return rw->answered_p;
  2269. }
  2270.  
  2271. /* gets the menu for the buffer/extent pair at the head of the request buffer.
  2272.    returns the propose choice request if succeeds, nil otherwise (kernel
  2273.    connection closed, or not connected)
  2274.  */
  2275.  
  2276. static Lisp_Object
  2277. get_energize_menu (Lisp_Object buffer, Lisp_Object extent_obj, int selection_p,
  2278.            Lisp_Object only_name)
  2279. {
  2280.   Connection*    conn;
  2281.   EId    buffer_id;
  2282.   EId    extent_id;
  2283.   Lisp_Object result;
  2284.   struct reply_wait rw;
  2285.   struct gcpro gcpro1, gcpro2;
  2286.  
  2287.   if (!get_energize_connection_and_buffer_id (buffer,
  2288.                           (void **) &conn,
  2289.                           (long *) &buffer_id))
  2290.     return Qnil;
  2291.  
  2292.   if (EXTENTP (extent_obj))
  2293.     extent_id = energize_extent_data_id (extent_to_data (extent_obj));
  2294.   else
  2295.     extent_id = 0;
  2296.  
  2297.   CWriteQueryChoicesRequest (conn, buffer_id, extent_id);
  2298.   conn->header->data =
  2299.     selection_p ? CEChasCharSelection | CEChasObjectSelection : 0;
  2300.   conn->header->serial = ++request_serial_number;
  2301.   CWriteRequestBuffer (conn);
  2302.  
  2303.   /* wait for the acknowledge */
  2304.   rw.serial = request_serial_number;
  2305.   rw.objectId = buffer_id;
  2306.   rw.genericId = extent_id;
  2307.   rw.menu_result = Qnil;
  2308.   rw.only_name = only_name;
  2309.  
  2310.   GCPRO2 (rw.menu_result, rw.only_name);
  2311.   wait_for_reply (&rw);
  2312.   result = rw.menu_result;
  2313.   UNGCPRO;
  2314.   return result;
  2315. }
  2316.  
  2317.  
  2318. static void
  2319. execute_energize_menu (Lisp_Object buffer, Energize_Extent_Data* ext,
  2320.                char* name, EId item_id, EId flags,
  2321.                Lisp_Object selection, Lisp_Object no_confirm)
  2322. {
  2323.   Connection*    conn;
  2324.   EId    buffer_id;
  2325.   EId    extent_id;
  2326.   BufferInfo*    binfo;
  2327.   struct reply_wait rw;
  2328.  
  2329.   if (!get_energize_connection_and_buffer_id (buffer, (void**)&conn,
  2330.                           (long*)&buffer_id))
  2331.     return;
  2332.  
  2333.   extent_id = energize_extent_data_id (ext);
  2334.  
  2335.   if ((flags & CKBuffer) && !NILP (Fbuffer_modified_p (buffer)))
  2336.     {
  2337.       /* saves buffer if requested and needed */
  2338.       binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
  2339.       if (binfo)
  2340.     write_energize_buffer_data (binfo);
  2341.     }
  2342.  
  2343.   CWriteExecuteChoicesRequest (conn, buffer_id, extent_id, item_id, 0, 0);
  2344.   /* send the menu name */
  2345.   if (energize_connection->minor >= 7)
  2346.     CWriteVstring0 (conn, name);
  2347.   conn->header->serial = ++request_serial_number;
  2348.   conn->header->data = 0;
  2349.   if (STRINGP (selection))
  2350.     {
  2351.       conn->header->data |= CEChasCharSelection;
  2352.       CWriteVstringLen (conn, string_data (XSTRING (selection)),
  2353.             string_length (XSTRING (selection)));
  2354.     }
  2355.   else if (VECTORP (selection))
  2356.     {
  2357.       int i;
  2358.       EId data;
  2359.       conn->header->data |= CEChasObjectSelection;
  2360.  
  2361.       /* writes the length */
  2362.       data = vector_length (XVECTOR (selection));
  2363.       CWrite (conn, EId, &data);
  2364.  
  2365.       /* writes the elements */
  2366.       for (i = 0; i < vector_length (XVECTOR (selection)); i++)
  2367.     {
  2368.       if (CONSP (vector_data (XVECTOR (selection)) [i]))
  2369.         data = lisp_to_word (vector_data (XVECTOR (selection)) [i]);
  2370.       else
  2371.         data = XINT (vector_data (XVECTOR (selection)) [i]);
  2372.       CWrite (conn, EId, &data);
  2373.     }
  2374.     }
  2375.   else if (CONSP (selection))
  2376.     {
  2377.       Lisp_Object type = Fcar (selection);
  2378.       Lisp_Object value = Fcdr (selection);
  2379.       if (EQ (type, intern ("ENERGIZE_OBJECT"))
  2380.       && STRINGP (value))
  2381.     {
  2382.       conn->header->data |= CEChasObjectSelection;
  2383.       CWriteN (conn, char, string_data (XSTRING (value)),
  2384.            string_length (XSTRING (value)));
  2385.     }
  2386.     }
  2387.   else if (!NILP (selection))
  2388.     error ("unrecognised energize selection");
  2389.   
  2390.   if (!NILP (no_confirm))
  2391.     conn->header->data |= CECnoConfirm;
  2392.   CWriteLength (conn);
  2393.   CWriteRequestBuffer (conn);
  2394.  
  2395.   /* wait for the acknowledge */
  2396.   rw.serial = request_serial_number;
  2397.   rw.objectId = buffer_id;
  2398.   rw.genericId = extent_id;
  2399.   rw.itemId = item_id;
  2400.   rw.message = 0;
  2401.  
  2402.   if (wait_for_reply (&rw) && !rw.status)
  2403.     {
  2404.       char message [128];
  2405.       if (energize_connection && energize_connection->conn)
  2406.     sprintf (message, IDENTITY_CRISIS " command failed: %.80s",
  2407.          (rw.message ? rw.message : "(null)"));
  2408.       else
  2409.     sprintf (message, "Connection to " IDENTITY_CRISIS " was closed.");
  2410.       if (rw.message)
  2411.     xfree (rw.message);
  2412.       error (message);
  2413.     }
  2414.   else
  2415.     {
  2416.       if (rw.message)
  2417.     xfree (rw.message);
  2418.       if (!energize_connection)
  2419.     error ("Connection to " IDENTITY_CRISIS " was closed.");
  2420.     }
  2421.  }
  2422.  
  2423. /* Returns a list of vectors representing the menu choices.  Next request
  2424.    in connection must be a ProposeChoices.  The list is
  2425.    (buffer extent <item1> ... <itemN>).     <itemI> is (name id1 id2 flags).
  2426.    Idi is (high .  low).  We build the list in reverse order and nreverse
  2427.    it.    If (only_name != 0), we only return the item of named only_name as
  2428.    a vector.  */
  2429.  
  2430. static Lisp_Object
  2431. list_choices (Lisp_Object buffer, Lisp_Object extent_obj,
  2432.           Lisp_Object only_name, CProposeChoicesRequest* creq)
  2433. {
  2434.   Connection *conn;
  2435.   int i;
  2436.   Lisp_Object item_list;
  2437.   Lisp_Object item;
  2438.   struct Lisp_Vector *v;
  2439.   struct gcpro gcpro1, gcpro2, gcpro3;
  2440.   CChoice *choice;
  2441.   ReqLen name_length;
  2442.   char *name;
  2443.   char *arg_name;
  2444.  
  2445.   if (energize_connection && energize_connection->conn)
  2446.     conn = energize_connection->conn;
  2447.   else
  2448.     return Qnil;
  2449.  
  2450.   if (!creq || creq->head.reqType != ProposeChoicesRType)
  2451.     {
  2452.       CSkipRequest (conn);
  2453.       return Qnil;
  2454.     }
  2455.  
  2456.   item = Qnil;
  2457.   item_list = Qnil;
  2458.  
  2459.   GCPRO3 (only_name, item_list, item);
  2460.  
  2461.   for (i = 0; i < (int)(creq->nChoices); i++)
  2462.     {
  2463.       choice = CGet (conn, CChoice);
  2464.       name = CGetVstring (conn, &name_length);
  2465.       if (!name_length)
  2466.     continue;
  2467.  
  2468.       /* the argument, if passed, is another string after the NUL (!)
  2469.        * this is a quick hack to provide cheap arguments to menus entries */
  2470.       arg_name = strchr (name, 0240);
  2471.       if (arg_name)
  2472.     {
  2473.       *arg_name= 0;
  2474.       arg_name += 1;
  2475.     }
  2476.  
  2477.       if (!NILP (only_name))
  2478.     {
  2479.       if (!strcmp ((char*) string_data (XSTRING (only_name)), name))
  2480.         {
  2481.           if (NILP (item))
  2482.         {
  2483.           item = make_vector (5, Qnil);
  2484.           v = XVECTOR (item);
  2485.           v->contents [0] = only_name;
  2486.         }
  2487.           v->contents [1] = word_to_lisp (choice->choiceId);
  2488.           v->contents [2] = Qnil;
  2489.           v->contents [3] = make_number (choice->flags);
  2490.           v->contents [4] = arg_name ? build_string (arg_name) : Qnil;
  2491.         }
  2492.     }
  2493.       else
  2494.     {
  2495.       item = make_vector (5, Qnil);
  2496.       v = XVECTOR (item);
  2497.       v->contents [0] = build_string (name);
  2498.       v->contents [1] = word_to_lisp (choice->choiceId);
  2499.       v->contents [2] = Qnil;
  2500.       v->contents [3] = make_number (choice->flags);
  2501.       v->contents [4] = arg_name ? build_string (arg_name) : Qnil;
  2502.       item_list = Fcons (item, item_list); /* pushes in the list */
  2503.     }
  2504.     }
  2505.  
  2506.   if (NILP (only_name))
  2507.     item_list = Fcons (buffer, Fcons (extent_obj, Fnreverse (item_list)));
  2508.   UNGCPRO;
  2509.  
  2510.   return NILP (only_name) ? item_list : item;
  2511. }
  2512.  
  2513. DEFUN ("energize-list-menu", Fenergize_list_menu,
  2514.        Senergize_list_menu, 3, 4, 0,
  2515.        "Request the set of menu options from the Energize server that are\n\
  2516. appropriate to the buffer and the extent.  Extent can be (), in which case\n\
  2517. the options are requested for the whole buffer.     Selection-p tells\n\
  2518. if the selection is available on the dislpay emacs is using. \n\
  2519. Returns the options as\n\
  2520. a list that can be passed to energize-activate-menu.  Items\n\
  2521. in the list can also be passed to energize-execute-menu-item.\n\
  2522. The list is (buffer extent or () <item1> ... <itemN>).\n\
  2523. where <itemI> is (name id1 id2 flags); idI is (high . low).\n\
  2524. If optional argument only-name is provided only the item with name only-name\n\
  2525. is returned, or () if no such item exists.")
  2526.      (buffer, extent_obj, selection_p, only_name)
  2527.      Lisp_Object buffer, extent_obj, selection_p, only_name;
  2528. {
  2529.   Lisp_Object res;
  2530.   CHECK_BUFFER (buffer, 1);
  2531.  
  2532.   if (!energize_connection || !energize_connection->conn) return Qnil;
  2533.  
  2534.   if (!NILP (only_name))
  2535.     CHECK_STRING (only_name, 1);
  2536.  
  2537.   res = get_energize_menu (buffer, extent_obj, !NILP (selection_p),
  2538.                only_name);
  2539.   notify_delayed_requests ();
  2540.   return res;
  2541. }
  2542.  
  2543. DEFUN ("energize-execute-menu-item", Fenergize_execute_menu_item,
  2544.        Senergize_execute_menu_item, 3, 5, 0,
  2545.        "Item is a vector received by energize-list-menu.  Sends a request to\n\
  2546. execute the code associated to this menu inside the Energize server.\n\
  2547. Optional fourth argument is a string or a vector to be used as the selection\n\
  2548. for entry disabled because they need the selection.\n\
  2549. Optional fifth argument, if non NIL, tells Energize to not request \n\
  2550. confirmation before executing the command.")
  2551. (buffer, extent_obj, item, selection, no_confirm)
  2552. Lisp_Object buffer, extent_obj, item, selection, no_confirm;
  2553. {
  2554.   struct Lisp_Vector *v;
  2555.  
  2556.   if (!energize_connection || !energize_connection->conn) return Qnil;
  2557.  
  2558.   CHECK_BUFFER (buffer, 1);
  2559.   CHECK_VECTOR (item, 1);
  2560.   v = XVECTOR (item);
  2561.  
  2562.   if (vector_length (v) != 4)
  2563.     error ("Bad menu item to energize-execute-menu-item");
  2564.  
  2565.   /* ignore the flags for now */
  2566.   execute_energize_menu (buffer, extent_to_data (extent_obj),
  2567.              (char*)string_data (XSTRING (v->contents [0])),
  2568.              lisp_to_word (v->contents [1]),
  2569.              XINT (v->contents [3]),
  2570.              selection,
  2571.              no_confirm);
  2572.  
  2573.   return Qt;
  2574. }
  2575.  
  2576. DEFUN ("energize-execute-command-internal", Fenergize_execute_command_internal,
  2577.        Senergize_execute_command_internal, 3, 5, 0,
  2578.        "Command is a string naming an energize command.     Sends a request to\n\
  2579. execute this command inside the Energize server.\n\
  2580. Optional fourth argument is a string or a vector to be used as the selection.\n\
  2581. Optional fifth argument, if non NIL, tells Energize to not request \n\
  2582. confirmation before executing the command.\n\
  2583. \n\
  2584. See also 'energize-list-menu'.")
  2585.      (buffer, extent_obj, command, selection, no_confirm)
  2586.      Lisp_Object buffer, extent_obj, command, selection, no_confirm;
  2587. {
  2588.   if (!energize_connection || !energize_connection->conn) return Qnil;
  2589.  
  2590.   CHECK_BUFFER (buffer, 1);
  2591.   CHECK_STRING (command, 1);
  2592.  
  2593.   execute_energize_menu (buffer, extent_to_data (extent_obj),
  2594.              (char*)string_data (XSTRING (command)), 0, 0, selection,
  2595.              no_confirm);
  2596.  
  2597.   return Qt;
  2598. }
  2599.  
  2600. /********************************* kill buffer interface ****************/
  2601.  
  2602. DEFUN ("energize-buffer-type-internal",
  2603.        Fenergize_buffer_type, Senergize_buffer_type,
  2604.        1, 1, 0,
  2605.        "Return a symbol denoting the buffer type if buffer is an Energize\n\
  2606. buffer, else it returns NIL.")
  2607.     (buffer)
  2608.     Lisp_Object buffer;
  2609. {
  2610.   if (!energize_connection) return Qnil;
  2611.  
  2612.   CHECK_BUFFER (buffer, 1);
  2613.   return get_buffer_type_for_emacs_buffer (buffer, energize_connection);
  2614. }
  2615.  
  2616. DEFUN ("set-energize-buffer-type-internal",
  2617.        Fset_energize_buffer_type_internal,
  2618.        Sset_energize_buffer_type_internal, 2, 2, 0,
  2619.  "Return the type symbol which is the new buffer-type, if the buffer is\n\
  2620. an Energize buffer and the type is non-NIL symbol, else it returns NIL.")
  2621.    (buffer, type)
  2622.     Lisp_Object buffer, type;
  2623. {
  2624.   BufferInfo *binfo;
  2625.  
  2626.   if (!energize_connection || (NILP (type))) return Qnil;
  2627.  
  2628.   CHECK_BUFFER (buffer, 1);
  2629.   CHECK_SYMBOL (type, 1);
  2630.  
  2631.   if (!(binfo =
  2632.     get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
  2633.     return Qnil;
  2634.   else
  2635.     return
  2636.       set_buffer_type_for_emacs_buffer (buffer, energize_connection, type);
  2637. }
  2638.  
  2639. DEFUN ("energize-buffer-p", Fenergize_buffer_p, Senergize_buffer_p, 1, 1, 0,
  2640.        "Whether buffer is an Energize buffer.")
  2641.   (buffer)
  2642.   Lisp_Object buffer;
  2643. {
  2644.   BufferInfo *binfo;
  2645.  
  2646.   if (!energize_connection) return Qnil;
  2647.  
  2648.   CHECK_BUFFER (buffer, 1);
  2649.   if (!(binfo =
  2650.     get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
  2651.     return Qnil;
  2652.   else
  2653.     return Qt;
  2654. }
  2655.  
  2656. DEFUN ("energize-buffer-id", Fenergize_buffer_id, Senergize_buffer_id, 1, 1, 0,
  2657.        "Return (high . low) if buffer is an Energize buffer, otherwise nil.")
  2658.      (buffer)
  2659.      Lisp_Object buffer;
  2660. {
  2661.   BufferInfo *binfo;
  2662.  
  2663.   if (!energize_connection) return Qnil;
  2664.  
  2665.   CHECK_BUFFER (buffer, 1);
  2666.   if (!(binfo =
  2667.     get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
  2668.     return Qnil;
  2669.   else
  2670.     return word_to_lisp (binfo->id);
  2671. }
  2672.  
  2673. DEFUN ("energize-request-kill-buffer", Fenergize_request_kill_buffer,
  2674.        Senergize_request_kill_buffer, 1, 1, 0,
  2675.        "Sends a request to energize for killing buffer.")
  2676.    (buffer)
  2677.    Lisp_Object buffer;
  2678. {
  2679.   BufferInfo *binfo;
  2680.  
  2681.   if (!energize_connection) return Qnil;
  2682.  
  2683.   CHECK_BUFFER (buffer, 1);
  2684.   if (!(binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
  2685.     return Qnil;
  2686.  
  2687.   /* Tell Energize about it if connected */
  2688.   if (energize_connection->conn)
  2689.     {
  2690.       CWriteKillBufferHeader (energize_connection->conn, binfo->id);
  2691.       CWriteRequestBuffer (energize_connection->conn);
  2692.     }
  2693.  
  2694.   /* Clears the internal state */
  2695.   forget_buffer (binfo);
  2696.  
  2697.   return Qnil;
  2698. }
  2699.  
  2700. /******************** Handle requests from the kernel *********************/
  2701.  
  2702. #ifdef EMACS_BTL
  2703. #include "cadillac-btl-extern.h"
  2704. #endif
  2705.  
  2706. /* turn logging on or off, etc. */
  2707. static void
  2708. handle_logging_request (Editor *editor, CLoggingRequest *creq)
  2709.      /* I'm a lumberjack and I'm ok... */
  2710. {
  2711.   ReqLen name_len;
  2712.   char* data_filename = CGetVstring (editor->conn, &name_len);
  2713.  
  2714. #ifdef EMACS_BTL
  2715.   {
  2716.     char *execname =
  2717.       (STRINGP (Vinvocation_directory))?
  2718.     ((char *) string_data (XSTRING (Vinvocation_directory))):0;
  2719.  
  2720.     switch (creq->type)
  2721.       {
  2722.       case CLRInitBTL:
  2723.     cadillac_terminate_logging (); /* #### rename me */
  2724.     cadillac_initialize_backtrace_logging /* #### rename me */
  2725.       (data_filename, execname, (long) creq->limit, (long) creq->interval);
  2726.     break;
  2727.  
  2728.       case CLRInitPCL:
  2729.     cadillac_terminate_logging (); /* #### rename me */
  2730.     cadillac_initialize_pc_logging /* #### rename me */
  2731.       (data_filename, execname, (long) creq->limit, (long) creq->interval);
  2732.     break;
  2733.  
  2734.       case CLRStart:
  2735.     cadillac_start_logging (); /* #### rename me */
  2736.     break;
  2737.  
  2738.       case CLRStop:
  2739.     cadillac_stop_logging (); /* #### rename me */
  2740.     break;
  2741.  
  2742.       case CLRTerminate:
  2743.     cadillac_terminate_logging (); /* #### rename me */
  2744.     break;
  2745.  
  2746.       case CLRSetLogSignal:
  2747.     cadillac_set_log_signal (creq->signal); /* #### rename me */
  2748.     break;
  2749.  
  2750.       default:
  2751.     error ("Bad logging request type %d", creq->type);
  2752.       }
  2753.   }
  2754. #else
  2755.   message ("Logging request, but no such code in image.");
  2756. #endif
  2757. }
  2758.  
  2759.  
  2760.  
  2761. /* creates a new buffer */
  2762. static void
  2763. handle_new_buffer_request (Editor *editor, CNewBufferRequest *creq)
  2764. {
  2765.   read_energize_buffer_data (editor->conn, &creq->buffer, editor, 0, 0,
  2766.                  creq->transientId, 0);
  2767.   if (!NILP (Venergize_create_buffer_hook))
  2768.     {
  2769.       CBuffer *cbu = &creq->buffer;
  2770.       BufferInfo *binfo = get_buffer_info_for_id (cbu->bufferId, editor);
  2771.       Lisp_Object buffer;
  2772.       if (binfo)
  2773.     {
  2774.       Lisp_Object prev_frame;
  2775.       buffer = binfo->emacs_buffer;
  2776.       if (!NILP (binfo->frame))
  2777.         {
  2778.           prev_frame = Fselected_frame (Qnil);
  2779.           Fselect_frame (binfo->frame);
  2780.         }
  2781.       run_hook_with_args (Qenergize_create_buffer_hook, 1, buffer);
  2782.       if (!NILP (binfo->frame))
  2783.         Fselect_frame (prev_frame);
  2784.     }
  2785.     }
  2786. }
  2787.  
  2788. /* Modifies the contents of a buffer */
  2789. static void
  2790. handle_modify_buffer_request (Editor *editor, CModifyBufferRequest *creq)
  2791. {
  2792.   read_energize_buffer_data (editor->conn, &creq->newData, editor,
  2793.                  creq->startPosition, creq->endPosition,
  2794.                  0, creq->head.data);
  2795. }
  2796.  
  2797. static void
  2798. make_buffer_and_extent_visible (Lisp_Object list, Lisp_Object go_there)
  2799. {
  2800.   call2 (Qenergize_make_many_buffers_visible, list, go_there);
  2801. }
  2802.  
  2803. /* pops a buffer and scroll to a extent: calls to lisp */
  2804. static void
  2805. handle_ensure_visible_request (Editor *editor, CEnsureVisibleRequest *creq)
  2806. {
  2807.   BufferInfo *binfo;
  2808.   Energize_Extent_Data *ext;
  2809.   Lisp_Object buffer_extent_list;
  2810.   struct gcpro gcpro1;
  2811.  
  2812.   buffer_extent_list = Qnil;
  2813.   GCPRO1 (buffer_extent_list);
  2814.  
  2815.   binfo = get_buffer_info_for_id (creq->bufferId, editor);
  2816.   if (!binfo)
  2817.     {
  2818.       message ("EnsureVisibleRequest: unknown buffer");
  2819.       goto finished;
  2820.     }
  2821.  
  2822.   if (!NILP (binfo->frame))
  2823.     {
  2824.       /* ignore ensure visible for postit note buffers */
  2825.       goto finished;
  2826.     }
  2827.  
  2828.   if (creq->extentId)
  2829.     {
  2830.       ext = get_extent_data (creq->extentId, binfo);
  2831.       if (!ext)
  2832.     message ("EnsureVisibleRequest: ignoring unknown extent");
  2833.     }
  2834.   else
  2835.     ext = 0;
  2836.  
  2837.   buffer_extent_list = Fcons (ext ? data_to_extent (ext) : Qnil, Qnil);
  2838.   buffer_extent_list = Fcons (binfo->emacs_buffer, buffer_extent_list);
  2839.  
  2840.   make_buffer_and_extent_visible (buffer_extent_list, creq->head.data ? Qt : Qnil);
  2841.  
  2842.  finished:
  2843.   CSkipRequest (editor->conn);
  2844.   UNGCPRO;
  2845. }
  2846.  
  2847. static void
  2848. handle_ensure_many_visible_request (Editor *editor,
  2849.                     CEnsureManyVisibleRequest *creq)
  2850. {
  2851.   BufferInfo *binfo;
  2852.   Energize_Extent_Data *ext;
  2853.   Lisp_Object buffer_extent_list;
  2854.   int n;
  2855.   EId buffer_id;
  2856.   EId extent_id;
  2857.   struct gcpro gcpro1;
  2858.  
  2859.   buffer_extent_list = Qnil;
  2860.   GCPRO1 (buffer_extent_list);
  2861.  
  2862.   for (n = creq->head.data,
  2863.        buffer_id = creq->bufferId,
  2864.        extent_id = creq->extentId;
  2865.        n;
  2866.        n--,
  2867.        buffer_id = n ? *(CGet (editor->conn, EId)) : 0,
  2868.        extent_id = n ? *(CGet (editor->conn, EId)) : 0)
  2869.     {
  2870.       binfo = get_buffer_info_for_id (buffer_id, editor);
  2871.       if (!binfo)
  2872.     {
  2873.       message ("EnsureManyVisibleRequest: ignoring unknown buffer");
  2874.       continue;
  2875.     }
  2876.  
  2877.       if (!NILP (binfo->frame))
  2878.     {
  2879.       /* silently ignore ensure visible for postit note buffers */
  2880.       continue;
  2881.     }
  2882.  
  2883.       if (extent_id)
  2884.     {
  2885.       ext = get_extent_data (extent_id, binfo);
  2886.       if (!ext)
  2887.         message ("EnsureManyVisibleRequest: ignoring unknown extent");
  2888.     }
  2889.       else
  2890.     ext = 0;
  2891.  
  2892.       /* cons in reverse order and reverse the list before
  2893.      calling make_buffer_and_extent_visible */
  2894.       buffer_extent_list = Fcons (binfo->emacs_buffer, buffer_extent_list);
  2895.       buffer_extent_list = Fcons (ext ? data_to_extent (ext) : Qnil,
  2896.                   buffer_extent_list);
  2897.     }
  2898.   buffer_extent_list = Fnreverse (buffer_extent_list);
  2899.   make_buffer_and_extent_visible (buffer_extent_list, Qt);
  2900.  
  2901.   UNGCPRO;
  2902. }
  2903.  
  2904. /* Update the cached menus, ie update the menubar for now. */
  2905. static void
  2906. handle_propose_choices_request (Editor *editor, CProposeChoicesRequest *req)
  2907. {
  2908.   BufferInfo* binfo;
  2909.   Lisp_Object buffer = Qnil;
  2910.   Lisp_Object extent = Qnil;
  2911.   Lisp_Object choices = Qnil;
  2912.   struct gcpro gcpro1, gcpro2, gcpro3;
  2913.   struct reply_wait* rw;
  2914.  
  2915.   GCPRO3 (buffer, extent, choices);
  2916.  
  2917.   /* get the buffer */
  2918.   binfo = get_buffer_info_for_id (req->objectId, editor);
  2919.   if (binfo)
  2920.     buffer = binfo->emacs_buffer;
  2921.   else
  2922.     buffer = Qnil;
  2923.  
  2924.   /* get the extent */
  2925.   if (binfo && req->genericId)
  2926.     {
  2927.       Energize_Extent_Data* ext = get_extent_data (req->genericId, binfo);
  2928.       if (ext)
  2929.     extent = data_to_extent (ext);
  2930.       else
  2931.     extent = Qnil;
  2932.     }
  2933.   else
  2934.     extent = Qnil;
  2935.  
  2936.   /* find if we were waiting for a reply */
  2937.   rw = find_wait_reply (req->head.serial);
  2938.  
  2939.   /* handle the request */
  2940.   if (rw && rw->objectId == req->objectId && rw->genericId == req->genericId)
  2941.     {
  2942.       /* It's a reply for a get_energize_menu call */
  2943.       rw->answered_p = True;
  2944.       rw->status = 1;
  2945.       rw->menu_result = list_choices (buffer, extent, rw->only_name, req);
  2946.     }
  2947.   else
  2948.     {
  2949.       /* It's a menu update, call the hook */
  2950.       choices = list_choices (buffer, extent, Qnil, req);
  2951.       run_hook_with_args (Qenergize_menu_update_hook, 1, choices);
  2952.     }
  2953.   UNGCPRO;
  2954. }
  2955.  
  2956. /* Kills a buffer */
  2957. static void
  2958. unmodify_buffer_and_kill_it (Lisp_Object buffer)
  2959. {
  2960.   int speccount = specpdl_depth ();
  2961.  
  2962.   if (!BUFFER_LIVE_P (XBUFFER (buffer)))
  2963.     return;
  2964.  
  2965.   Fset_buffer_modified_p (Qnil, buffer);
  2966.  
  2967.   /* kill it.  This will call the Energize hook to do the right thing */
  2968.   Fkill_buffer (buffer);
  2969. }
  2970.  
  2971. static void
  2972. handle_kill_buffer_request (Editor *editor, CKillBufferRequest *creq)
  2973. {
  2974.   BufferInfo *binfo;
  2975.  
  2976.   if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
  2977.     {
  2978.       message ("KillBufferVisibleRequest: unregistered buffer");
  2979.       return;
  2980.     }
  2981.  
  2982.   unmodify_buffer_and_kill_it (binfo->emacs_buffer);
  2983. }
  2984.  
  2985. static void
  2986. handle_remove_extents_request (Editor *editor, CRemoveExtentsRequest *creq)
  2987. {
  2988.   BufferInfo *binfo;
  2989.   int i;
  2990.   EId *ids;
  2991.   Lisp_Object restore_buffer_state_cons;
  2992.   int speccount = specpdl_depth ();
  2993.  
  2994.   if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
  2995.     {
  2996.       message ("RemoveExtentsRequest: unregistered buffer");
  2997.       CSkipRequest (editor->conn);
  2998.       return;
  2999.     }
  3000.  
  3001.   /* enable buffer edits */
  3002.   restore_buffer_state_cons =
  3003.     Fcons (make_opaque_ptr ((void *) creq->bufferId),
  3004.        Fcons (XBUFFER (binfo->emacs_buffer)->read_only, Qnil));
  3005.  
  3006.   record_unwind_protect (restore_buffer_state, restore_buffer_state_cons);
  3007.  
  3008.   XBUFFER (binfo->emacs_buffer)->read_only = Qnil;
  3009.  
  3010.   /* save old hook values */
  3011.   specbind (Qenergize_buffer_modified_hook, Qnil);
  3012.  
  3013.   ids = CGetN (editor->conn, EId, creq->nExtent);
  3014.   for (i = 0; i < creq->nExtent; i++)
  3015.     {
  3016.       Energize_Extent_Data *ext = get_extent_data (ids [i], binfo);
  3017.       if (ext)
  3018.     free_Energize_Extent_Data (ext, binfo, OFT_STANDALONE);
  3019.     }
  3020.  
  3021.   /* restore modified hooks and globals */
  3022.   unbind_to (speccount, Qnil);
  3023. }
  3024.  
  3025. #ifndef ENERGIZE_V2_HEADERS
  3026. static Lisp_Object
  3027. save_to_energize_unwind (Lisp_Object closure)
  3028. {
  3029.   BITS32 buffer_id = (BITS32) cons_to_long (closure);
  3030.   /* If the buffer ID is not 0, then the call to save-buffer
  3031.      didn't complete normally - so tell Energize the save was aborted. */
  3032.   if (buffer_id)
  3033.     {
  3034.       Editor *editor = energize_connection;
  3035.       if (editor && editor->conn)  /* Maybe the kernel has gone away. */
  3036.     {
  3037.       CWriteBufferSaveAbortedHeader (editor->conn, buffer_id);
  3038.       CWriteRequestBuffer (editor->conn);
  3039.     }
  3040.     }
  3041.   return Qnil;
  3042. }
  3043. #endif /*  ENERGIZE_V2_HEADERS */
  3044.  
  3045.  
  3046. /* handles a request to save a buffer from the kernel */
  3047. static void
  3048. handle_save_buffer_request (Editor *editor, CSaveBufferRequest *creq)
  3049. {
  3050.   BufferInfo *binfo;
  3051.   int speccount = specpdl_depth ();
  3052.   struct gcpro gcpro1;
  3053.   Lisp_Object closure = Qnil;
  3054.  
  3055.   if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
  3056.     {
  3057.       message ("Server attempt to save a non registered buffer");
  3058.       return;
  3059.     }
  3060.  
  3061.   if (!EQ (binfo->emacs_buffer, Fcurrent_buffer ()))
  3062.     {
  3063.       record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
  3064.       Fset_buffer (binfo->emacs_buffer);
  3065.     }
  3066.  
  3067.   GCPRO1 (closure);
  3068.   if (creq->head.data == CSExecuteSave)
  3069.     {
  3070. #ifndef ENERGIZE_V2_HEADERS
  3071.       Lisp_Object closure = make_opaque_ptr ((void *) creq->bufferId);
  3072.       record_unwind_protect (save_to_energize_unwind, closure);
  3073. #endif /*  ENERGIZE_V2_HEADERS */
  3074.       call0 (intern ("save-buffer"));
  3075. #ifndef ENERGIZE_V2_HEADERS
  3076.       /* clear out the id to tell the unwind-protect form that the save
  3077.      completed normally. */
  3078.       set_opaque_ptr (closure, 0);
  3079. #endif /*  ENERGIZE_V2_HEADERS */
  3080.     }
  3081.   else
  3082.     write_energize_buffer_data (binfo);
  3083.  
  3084.   UNGCPRO;
  3085.   unbind_to (speccount, Qnil);
  3086. }
  3087.  
  3088. static void
  3089. handle_set_modified_flag_request (Editor* editor,
  3090.                   CSetModifiedFlagRequest* creq)
  3091. {
  3092.   BufferInfo *binfo;
  3093.   int speccount = specpdl_depth ();
  3094.  
  3095.   if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
  3096.     {
  3097.       message ("Server attempt to set modified flag of a non registered buffer");
  3098.       return;
  3099.     }
  3100.  
  3101.   record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
  3102.   specbind (Qenergize_buffer_modified_hook, Qnil);
  3103.  
  3104.   /* Only set buffer modified time in older protocols
  3105.      as we handle the file timestamps ourselves now for
  3106.      CBFileYourself buffers. */
  3107. #ifndef ENERGIZE_V2_HEADERS
  3108.   if ((energize_connection->minor < 10) && !(binfo->flags &  CBFileYourself))
  3109. #endif
  3110.     {
  3111.       Fset_buffer_modtime (binfo->emacs_buffer, Qnil);
  3112.     }
  3113.  
  3114.   Fset_buffer_modified_p (creq->state ? Qt : Qnil, binfo->emacs_buffer);
  3115.   binfo->modified_state = creq->state;
  3116.   /* Mark the buffer so that we ask permission to Energize when the
  3117.    * user tries to modify it again */
  3118.   binfo->editable = 0;
  3119.   if (!creq->state)
  3120.     mark_all_extents_as_unmodified (binfo);
  3121.   unbind_to (speccount, Qnil);
  3122. }
  3123.  
  3124.  
  3125. /* handles requests regarding p_sheet associated to buffers */
  3126. static void
  3127. add_in_list_of_ids (int** ids, int* n_ids, int id)
  3128. {
  3129.   if (*n_ids == 0)
  3130.     {
  3131.       *n_ids = 1;
  3132.       *ids = (int*)xmalloc (sizeof (int));
  3133.     }
  3134.   else
  3135.     {
  3136.       *n_ids += 1;
  3137.       *ids = (int*)xrealloc (*ids, sizeof (int) * (*n_ids));
  3138.     }
  3139.   (*ids) [(*n_ids) - 1] = id;
  3140. }
  3141.  
  3142. static void
  3143. remove_from_list_of_ids (int** ids, int* n_ids, int id)
  3144. {
  3145.   int i;
  3146.   if (*n_ids)
  3147.     {
  3148.       /* look for id in *ids */
  3149.       for (i = 0; i < (*n_ids) && (*ids) [i] != id; i++);
  3150.       /* shift the remaining ones */
  3151.       for (; i < (*n_ids) - 1; i++)
  3152.     (*ids) [i] = (*ids) [i + 1];
  3153.       /* decrease the count */
  3154.       *n_ids -= 1;
  3155.       /* free array if empty */
  3156.       if (!*n_ids)
  3157.     {
  3158.       xfree (*ids);
  3159.       *ids = 0;
  3160.     }
  3161.     }
  3162. }
  3163.  
  3164. extern void make_psheets_desired (struct frame *, Lisp_Object);
  3165.  
  3166. static void
  3167. handle_buffer_sheet_request (Editor *editor, CSheetRequest *sreq,
  3168.                  EId buffer_id)
  3169. {
  3170.   BufferInfo *binfo;
  3171.   char *name;
  3172.   Connection *conn = editor->conn;
  3173.  
  3174.   if (!(binfo = get_buffer_info_for_id (buffer_id, editor)))
  3175.     {
  3176.       message ("Server attempt to use p_sheet in a non registered buffer");
  3177.       CSkipRequest (conn);
  3178.       return;
  3179.     }
  3180.  
  3181.   name = CGetVstring (conn, (ReqLen *) 0);
  3182.   switch ((CSheetRSubtype) sreq->head.data)
  3183.     {
  3184.     case CSCreate:
  3185.       lw_register_widget (name, name, sreq->sheetId, NULL, NULL,
  3186.               handle_sheet_control_change, NULL);
  3187.       add_in_list_of_ids (&binfo->p_sheet_ids, &binfo->n_p_sheets,
  3188.               sreq->sheetId);
  3189.       if (!strcmp (name, DEBUGGER_PSHEET_NAME))
  3190.     debuggerpanel_sheet = sreq->sheetId;
  3191.       break;
  3192.  
  3193.     case CSDelete:
  3194.       remove_from_list_of_ids (&binfo->p_sheet_ids, &binfo->n_p_sheets,
  3195.                    sreq->sheetId);
  3196.       cleanly_destroy_all_widgets (1, &sreq->sheetId);
  3197.       if (sreq->sheetId == debuggerpanel_sheet)
  3198.     {
  3199.       desired_debuggerpanel_exposed_p = 0;
  3200.       debuggerpanel_sheet = 0;
  3201.     }
  3202.       break;
  3203.  
  3204.     case CSHide:
  3205.       {
  3206.     struct frame *frame;
  3207.     Lisp_Object rest;
  3208.  
  3209.     if (sreq->sheetId == debuggerpanel_sheet)
  3210.       desired_debuggerpanel_exposed_p = 0;
  3211.     else
  3212.       for (rest = DEVICE_FRAME_LIST (get_x_device(Qnil)); !NILP (rest); rest = Fcdr (rest))
  3213.         {
  3214.           frame = XFRAME (Fcar (rest));
  3215.           if (FRAME_IS_X (frame))
  3216.         make_psheets_desired (frame, Qnil);
  3217.         }
  3218.       }
  3219.       break;
  3220.  
  3221.     case CSShow:
  3222.       if (sreq->sheetId == debuggerpanel_sheet)
  3223.     desired_debuggerpanel_exposed_p = 1;
  3224.       else
  3225.     {
  3226.       struct frame *frame;
  3227.       struct window *window;
  3228.       Lisp_Object rest;
  3229.       for (rest = DEVICE_FRAME_LIST (get_x_device(Qnil)); !NILP (rest); rest = Fcdr (rest))
  3230.         {
  3231.           frame = XFRAME (Fcar (rest));
  3232.           if (FRAME_IS_X (frame))
  3233.         {
  3234.           window = XWINDOW (frame->selected_window);
  3235.           if (EQ (window->buffer, binfo->emacs_buffer))
  3236.             make_psheets_desired (frame, binfo->emacs_buffer);
  3237.         }
  3238.         }
  3239.     }
  3240.       break;
  3241.     }
  3242. }
  3243.  
  3244.  
  3245.  
  3246. /* show busy */
  3247.  
  3248. static void
  3249. show_all_menubars_busy (int busy)
  3250. {
  3251.   struct frame *f;
  3252.   Lisp_Object tail;
  3253.  
  3254.   for (tail = DEVICE_FRAME_LIST (get_x_device (Qnil)); CONSP (tail);
  3255.        tail = XCDR (tail))
  3256.     {
  3257.       f = XFRAME (XCAR (tail));
  3258.       if (FRAME_IS_X (f))
  3259.     {
  3260.       if (FRAME_X_MENUBAR_WIDGET (f))
  3261.         lw_show_busy (FRAME_X_MENUBAR_WIDGET (f), busy);
  3262.     }
  3263.     }
  3264. }
  3265.  
  3266. static void
  3267. handle_show_busy_request (Editor *editor, CGenericRequest *preq)
  3268. {
  3269.   /* call the show busy routine of the    library for the menubar of
  3270.    * all frames */
  3271.   ReqLen len;
  3272.  
  3273.   char* why = CGetVstring (editor->conn, &len);
  3274.  
  3275.   show_all_menubars_busy (preq->head.data);
  3276.   Venergize_kernel_busy = preq->head.data ? Qt : Qnil;
  3277.   run_hook_with_args (Qenergize_kernel_busy_hook, 1, build_string (why));
  3278. }
  3279.  
  3280. /* This request creates, destroys, raises, or lowers a psheet or dialog box.
  3281.  */
  3282. static void
  3283. handle_sheet_request (Connection* conn, CSheetRequest* sreq, Widget parent)
  3284. {
  3285.   char* name = CGetVstring (conn, NULL);
  3286.  
  3287.   switch ((CSheetRSubtype)sreq->head.data)
  3288.     {
  3289.     case CSCreate:
  3290.       lw_create_widget (name, name, sreq->sheetId, 0, parent,
  3291.             !sreq->bufferId, 0, handle_sheet_control_change, 0);
  3292.       break;
  3293.     case CSDelete:
  3294.       cleanly_destroy_all_widgets (1, &sreq->sheetId);
  3295.       break;
  3296.  
  3297.     case CSShow:
  3298.       lw_pop_up_all_widgets (sreq->sheetId);
  3299.       break;
  3300.  
  3301.     case CSHide:
  3302.       lw_pop_down_all_widgets (sreq->sheetId);
  3303.       break;
  3304.     }
  3305. }
  3306.  
  3307. /* This request changes slot values in the psheets/dialog boxes. */
  3308. static void
  3309. handle_set_control_request (Connection* conn, CGenericRequest* creq)
  3310. {
  3311.   CSetControlRequest* sreq = &creq->setcontrol;
  3312.   widget_value val;
  3313.   widget_value* contents;
  3314.  
  3315.   unsigned long i;
  3316.   unsigned long n = sreq->nChoices;
  3317.  
  3318.   if (n > 0)
  3319.     {
  3320.       contents = (widget_value *) xmalloc (n * sizeof (widget_value));
  3321.       memset (contents, 0, (n * sizeof (widget_value)));
  3322.     }
  3323.   else
  3324.     contents = NULL;
  3325.   memset (&val, 0, sizeof (val));
  3326.   val.name = CGetVstring (conn, NULL);
  3327.   val.enabled = !(sreq->flags & CKInactive);
  3328.   val.selected = !!(sreq->flags & CKSelected);
  3329.   val.change = VISIBLE_CHANGE;
  3330.   val.contents = contents;
  3331.  
  3332.   for (i = 0; i < n; i++)
  3333.     {
  3334.       widget_value* cur = &contents [i];
  3335.       CChoice* choice = CGet (conn, CChoice);
  3336.       cur->name = CGetVstring (conn, NULL);
  3337.       cur->value = cur->name;
  3338.       cur->key = NULL;
  3339.       cur->enabled = !(choice->flags & CKInactive);
  3340.       cur->selected = !!(choice->flags & CKSelected);
  3341.       cur->change = VISIBLE_CHANGE;
  3342.       cur->contents = NULL;
  3343.       cur->call_data = NULL;
  3344.       cur->next = i == n - 1 ? NULL : &contents [i + 1];
  3345.       cur->toolkit_data = NULL;
  3346.       if ((i == 0 && n == 1) || cur->selected)
  3347.     {
  3348.       val.value = cur->name;
  3349.       if (!*val.value)
  3350.         val.value = NULL;
  3351.     }
  3352.     }
  3353.   lw_modify_all_widgets (sreq->sheetId, &val, True);
  3354.  
  3355.   if (contents)
  3356.     xfree (contents);
  3357. }
  3358.  
  3359. static void
  3360. handle_sheet_control_change (Widget widget, EId sheet_id, void* arg)
  3361. {
  3362.   Connection*    conn;
  3363.   widget_value* val;
  3364.   widget_value* cur;
  3365.   widget_value* this_val = NULL;
  3366.   widget_value* cancel = NULL;
  3367.   char*        this_name;
  3368.   int delete_window_p = (((int) arg) == -1);
  3369.  
  3370.  
  3371.   if (!energize_connection)
  3372.     return;
  3373.  
  3374.   conn = energize_connection->conn;
  3375.   if (!conn)
  3376.     return;
  3377.  
  3378.   this_name = XtName (widget);
  3379.   val = lw_get_all_values (sheet_id);
  3380.  
  3381.   if (delete_window_p)
  3382.     /* Complete and utter kludge.  If this dbox was dismissed with the
  3383.        WM close box (WM_DELETE_WINDOW, meaning the widget was destroyed)
  3384.        then we look for a likely "cancel" button and pretend the user
  3385.        clicked on that.     Really the protocol should be extended for this.
  3386.      */
  3387.     for (cur = val; cur; cur = cur->next)
  3388.       {
  3389.     char *v = cur->value;
  3390.     if (v &&
  3391.         ((strlen (v) >= 6 && !strncmp (v, "cancel", 6)) ||
  3392.          (strlen (v) >= 5 && !strncmp (v, "abort", 5))))
  3393.       cancel = cur;
  3394.       }
  3395.  
  3396.   /* first send all the edited widgets */
  3397.   for (cur = val; cur; cur = cur->next)
  3398.     {
  3399.       /* do not send the widget that ran the callback */
  3400.       if (!strcmp (cur->name, this_name))
  3401.     this_val = cur;
  3402.       else if (cur == cancel)
  3403.     ;
  3404.       /* send the edited widgets */
  3405.       else if (cur->edited)
  3406.     {
  3407.       char* value = cur->value;
  3408.       unsigned int flags = 0;
  3409.  
  3410.       if (!cur->enabled)
  3411.         flags |= CKInactive;
  3412.       if (cur->selected)
  3413.         flags |= CKSelected;
  3414.  
  3415.       /* the kernel is brain dead and expect "1" and "0" as values
  3416.          for the checkbox objects.    So if value is NULL, make it be "0"
  3417.          or "1" depending on the selected state.  This is until we fix
  3418.          the kernel. */
  3419.       if (!value)
  3420.         value = cur->selected ? "1" : "0";
  3421.  
  3422.       CWriteSetControlRequest (conn, sheet_id, 0, cur->name, 1);
  3423.       CWriteChoice (conn, 0, flags, value, 0);
  3424.       CWriteLength (conn);
  3425.     }
  3426.     }
  3427.  
  3428.   if (delete_window_p && !this_val)
  3429.     {
  3430.       this_val = cancel;
  3431. /*    if (! this_val) abort (); */
  3432.     }
  3433.  
  3434.   /* Then send the widget that ran the callback */
  3435.   if (this_val)
  3436.     {
  3437.       CWriteSetControlRequest (conn, sheet_id, 0, this_val->name, 1);
  3438.       CWriteChoice (conn, 0, 0, this_val->value, 0);
  3439.       CWriteLength (conn);
  3440.       CWriteRequestBuffer (conn);
  3441.     }
  3442. }
  3443.  
  3444. /******************** Low level connection stuff ************************/
  3445. static void
  3446. add_in_connection_input_buffer (Connection *conn, char *s, int l)
  3447. {
  3448.   /* Should be in connection.c */
  3449.   if (conn->inread >= conn->infill)
  3450.     conn->inread = conn->infill = conn->inbuffer;
  3451.  
  3452.   CNeedInputSize (conn, l);
  3453.   memcpy (conn->infill, s, l);
  3454.   conn->infill += l;
  3455. }
  3456.  
  3457. static Lisp_Object
  3458. process_one_energize_request ()
  3459. {
  3460.   Editor *editor = energize_connection;
  3461.   CEditorRequest *req;
  3462.   int res = 0;
  3463.  
  3464.   if (!editor) return make_number (res);
  3465.  
  3466.   if (!editor->conn)
  3467.     {
  3468.       close_energize_connection ();
  3469.       return make_number (res);
  3470.     }
  3471.  
  3472.   req = CReadEditorRequest (editor->conn);
  3473.   if (!req)
  3474.     {
  3475.       switch (errno)
  3476.     {
  3477.     case EWOULDBLOCK:
  3478.       /* message ("ProcessEnergizeRequest: internal error EWOULDBLOCK"); */
  3479.       res = -1;
  3480.       break;
  3481.  
  3482.     case 0:
  3483.     case ECONNRESET:
  3484.       message ("Connection to " IDENTITY_CRISIS " was closed.");
  3485.       close_energize_connection ();
  3486.       break;
  3487.  
  3488.     default:
  3489.       message
  3490.         ("System error on connection to " IDENTITY_CRISIS ", closing.");
  3491.       close_energize_connection ();
  3492.       break;
  3493.     }
  3494.     }
  3495.   else
  3496.     {
  3497.       res = 1;
  3498.       switch (req->head.reqType)
  3499.     {
  3500.     case RefuseConnectionRType:
  3501.       message (IDENTITY_CRISIS " connection refused");
  3502.       close_energize_connection ();
  3503.       break;
  3504.  
  3505.     case AcceptConnectionRType:
  3506.       {
  3507.         CProtocol* proto = CGet (editor->conn, CProtocol);
  3508.         editor->major = proto->major;
  3509.         editor->minor = proto->minor;
  3510.         message (IDENTITY_CRISIS " connection accepted");
  3511.         CSkipRequest (editor->conn);
  3512.       }
  3513.       break;
  3514.  
  3515.     case NewBufferRType:
  3516.       handle_new_buffer_request (editor, &req->newbuffer);
  3517.       break;
  3518.  
  3519.     case QueryBufferRType:
  3520.       {
  3521.         EId buffer_id;
  3522.         struct reply_wait* rw = find_wait_reply (req->head.serial);
  3523.         CGetVstring (editor->conn, 0); /* skip directory */
  3524.         CGetVstring (editor->conn, 0); /* skip file */
  3525.         buffer_id = *CGet (editor->conn, EId);
  3526.         if (rw)
  3527.           {
  3528.         rw->answered_p = 1;
  3529.         rw->status = req->head.data;
  3530.         rw->objectId = buffer_id;
  3531.           }
  3532.       }
  3533.       break;
  3534.  
  3535.     case EnsureVisibleRType:
  3536.       handle_ensure_visible_request (editor, &req->ensurevisible);
  3537.       break;
  3538.  
  3539.     case EnsureManyVisibleRType:
  3540.       handle_ensure_many_visible_request (editor, &req->ensuremanyvisible);
  3541.       break;
  3542.  
  3543.     case ModifyBufferRType:
  3544.       handle_modify_buffer_request (editor, &req->modifybuffer);
  3545.       break;
  3546.  
  3547.     case ProposeChoicesRType:
  3548.       handle_propose_choices_request (editor,
  3549.                       &req->generic.proposechoices);
  3550.       break;
  3551.  
  3552.     case ChoiceExecutedRType:
  3553.       {
  3554.         struct reply_wait* rw = find_wait_reply (req->head.serial);
  3555.         CChoiceExecutedRequest* ce = &req->generic.choiceexecuted;
  3556.         if (rw)
  3557.           {
  3558.         rw->answered_p = 1;
  3559.         rw->status = ce->head.data;
  3560.         rw->message = CMakeVstring (editor->conn, 0);
  3561.           }
  3562.       }
  3563.       break;
  3564.  
  3565.     case KillBufferRType:
  3566.       handle_kill_buffer_request (editor, &req->killbuffer);
  3567.       break;
  3568.  
  3569.     case ModifiedBufferRType:
  3570.       {
  3571.         struct reply_wait* rw = find_wait_reply (req->head.serial);
  3572.         if (rw)
  3573.           {
  3574.         rw->answered_p = 1;
  3575.         if (rw->objectId == req->modifiedbuffer.bufferId)
  3576.           rw->status = req->modifiedbuffer.state;
  3577.         else
  3578.           rw->status = CMBufferLocked;
  3579.           }
  3580.       }
  3581.       break;
  3582.  
  3583.     case SetModifiedFlagRType:
  3584.       handle_set_modified_flag_request (editor, &req->setmodifiedflag);
  3585.       break;
  3586.  
  3587.     case RemoveExtentsRType:
  3588.       handle_remove_extents_request (editor, &req->removeextents);
  3589.       break;
  3590.  
  3591.     case RenumberExtentsRType:
  3592.       /* HandleDuplicateExtentRequest (editor, req); */
  3593.       break;
  3594.  
  3595. #if 0
  3596.     case DialogRType:
  3597.       /* HandleDialogRequest (editor, req, CurrentBuffer (editor)); */
  3598.       break;
  3599. #endif
  3600.  
  3601.     case SaveBufferRType:
  3602.       handle_save_buffer_request (editor, &req->savebuffer);
  3603.       break;
  3604.  
  3605.     case SheetRType:{
  3606.       EId buffer_id = req->generic.sheet.bufferId;
  3607.       if (!buffer_id)
  3608.         buffer_id = buffer_id_of_sheet (req->generic.sheet.sheetId);
  3609.       if (buffer_id)
  3610.         handle_buffer_sheet_request (editor, &req->generic.sheet,
  3611.                      buffer_id);
  3612.       else
  3613.         {
  3614.           CSheetRSubtype type = (CSheetRSubtype)req->head.data;
  3615.           if (type == CSDelete || type ==CSHide)
  3616.         /* #### ??? this does nothing. */
  3617.         Fselect_frame (Fselected_frame (Qnil));
  3618.           handle_sheet_request (editor->conn, &req->generic.sheet,
  3619.                     FRAME_X_SHELL_WIDGET
  3620.                     (XFRAME (Fselected_frame (Qnil))));
  3621.         }
  3622.     }
  3623.       break;
  3624.  
  3625.     case SetControlRType:
  3626.       handle_set_control_request (editor->conn, (CGenericRequest*) req);
  3627.       break;
  3628.  
  3629.     case OpenPostitRType:
  3630.     case KillPostitRType:
  3631.       message ("Don't know what to do with postit requests.");
  3632.       break;
  3633.  
  3634.     case ShowBusyRType:
  3635.       handle_show_busy_request (editor, (CGenericRequest*)req);
  3636.       break;
  3637.  
  3638.     case LoggingRType:
  3639.       handle_logging_request (editor, (CLoggingRequest*)req);
  3640.       break;
  3641.  
  3642. #ifndef ENERGIZE_V2_HEADERS
  3643.     case KernelEventRType:
  3644.       CSkipRequest (editor->conn);
  3645.       break;
  3646. #endif
  3647.  
  3648.     default:
  3649.       message("ProcessEnergizeRequest: can't handle request of type %d",
  3650.         req->head.reqType);
  3651.     }
  3652.  
  3653.     }
  3654.  
  3655.   return make_number (res);
  3656. }
  3657.  
  3658. static int inside_process_energize_request_1;
  3659.  
  3660. /* this must be called ONLY by unwind_protect in process_energize_request_1 */
  3661. static Lisp_Object
  3662. post_handle_request (Lisp_Object ignored)
  3663. {
  3664.   if (inside_process_energize_request_1 <= 0)
  3665.     abort ();
  3666.   inside_process_energize_request_1--;
  3667.   if (energize_connection && energize_connection->conn)
  3668.     CSkipRequest (energize_connection->conn);
  3669.   return Qnil;
  3670. }
  3671.  
  3672. static Lisp_Object
  3673. pop_conn (Lisp_Object arg)
  3674. {
  3675.   Connection *old_conn = (Connection *) get_opaque_ptr (arg);
  3676.   if (! old_conn)
  3677.     abort ();
  3678.   if (! energize_connection)
  3679.     return Qnil;
  3680.   if (energize_connection->conn == old_conn)
  3681.     abort ();
  3682.  
  3683.   if (CRequestDelayedP (energize_connection->conn))
  3684.     /* We don't call the CWait* functions any more so this shouldn't happen.
  3685.        But if it does someday, then we need to either copy the remaining
  3686.        bits from new_conn to old_conn, or loop processing requests until
  3687.        new_conn is drained.
  3688.      */
  3689.     abort ();
  3690.  
  3691.   DeleteConnection (energize_connection->conn);
  3692.   energize_connection->conn = old_conn;
  3693.  
  3694.   return Qnil;
  3695. }
  3696.  
  3697. static Lisp_Object
  3698. process_energize_request_1 ()
  3699. {
  3700.   Lisp_Object result;
  3701.   int speccount = specpdl_depth ();
  3702.  
  3703.   if (inside_process_energize_request_1)
  3704.     {
  3705.       /* When the energize process filter is called recursively, push a new
  3706.      connection object.  The read-pointer of the connection buffer could
  3707.      be in the middle of a request.     However, we know that the fd itself
  3708.      is always pointing between requests.  So making a new connection is
  3709.      a way of skipping past the one request we were in the process of
  3710.      reading when we allowed process output to be handled recursively.
  3711.        */
  3712.       Connection *old_conn = energize_connection->conn;
  3713.       Connection *new_conn =
  3714.     make_energize_connection ((void *) energize_connection,
  3715.                   old_conn->fdin, old_conn->fdout);
  3716.       energize_connection->conn = new_conn;
  3717.       record_unwind_protect (pop_conn, make_opaque_ptr (old_conn));
  3718.     }
  3719.  
  3720.   /* this must come after pop_conn() to get the right connection object */
  3721.   record_unwind_protect (post_handle_request, Qnil);
  3722.  
  3723.   inside_process_energize_request_1++;
  3724.  
  3725.   result = process_one_energize_request ();
  3726.   notify_delayed_requests ();
  3727.  
  3728.   /* decrements inside_process_energize_request_1 and possibly replaces
  3729.      energize_connection->conn with old_conn.
  3730.    */
  3731.   unbind_to (speccount, Qnil);
  3732.  
  3733.   return result;
  3734. }
  3735.  
  3736.  
  3737. /******** Initialize Energize-related state and set up connection ********/
  3738.  
  3739. static void
  3740. setup_connection (Editor *ed, unsigned int id1, unsigned int id2)
  3741. {
  3742.   CEditorRequest *req = CWriteEditorRequest (ed->conn, QueryConnectionRType);
  3743.  
  3744.   /* these 2 slots are ignored */
  3745.   req->generic.queryconnection.major = 0;
  3746.   req->generic.queryconnection.minor = 0;
  3747.  
  3748.   req->generic.queryconnection.cadillacId1 = id1;
  3749.   req->generic.queryconnection.cadillacId2 = id2;
  3750.   req->generic.queryconnection.nProtocols = 1;
  3751.   /* first numerical arg is major protocol number, second is minor */
  3752.   CWriteProtocol (ed->conn, 0, 10, "editor");
  3753.   CWriteLength (ed->conn);
  3754.   CWriteRequestBuffer (ed->conn);
  3755. }
  3756.  
  3757. /* this is used as the readMethod of the energize connection, so that
  3758.    the connection library won't do some buffering that messes us up.
  3759.    It does this buffering only if conn->readMethod == read, so using
  3760.    another function turns it off.
  3761.  */
  3762. static int
  3763. my_read (int fd, char *buf, int nb)
  3764. {
  3765.   return read (fd, buf, nb);
  3766. }
  3767.  
  3768. static Connection *
  3769. make_energize_connection (Editor *editor, int fdin, int fdout)
  3770. {
  3771.   Connection *conn = NewConnection ((void *)editor, fdin, fdout);
  3772.   if (conn)
  3773.     conn->readMethod = my_read;
  3774.   return conn;
  3775. }
  3776.  
  3777. DEFUN ("handle-energize-request", Fhandle_energize_request,
  3778.        Shandle_energize_request,
  3779.        2, 2, 0,
  3780.        "Filter called when a request is available from Energize.")
  3781.      (proc, string)
  3782.      Lisp_Object proc, string;
  3783. {
  3784.   if (!NILP (string))
  3785.     CHECK_STRING (string, 0);
  3786.  
  3787.   if (!energize_connection || !energize_connection->conn)
  3788.     {
  3789.       /* no need for a message here, Energize is dead */
  3790.       return make_number (0);
  3791.     }
  3792.   if (!energize_connection || (!EQ (energize_connection->proc, proc)))
  3793.     {
  3794.       message ("Got " IDENTITY_CRISIS " request but not from current connection ");
  3795.       return make_number (0);
  3796.     }
  3797.  
  3798.   if (!NILP (string))
  3799.     add_in_connection_input_buffer (energize_connection->conn,
  3800.                     (char *) string_data (XSTRING (string)),
  3801.                     string_length (XSTRING (string)));
  3802.  
  3803.   return process_energize_request_1 ();
  3804. }
  3805.  
  3806.  
  3807. Lisp_Object Venergize_process;
  3808.  
  3809. /* Opens a network connection to Energize.
  3810.  * server is a string.    It can end up with :<uid> or :<username>
  3811.  * in which case the uid is added to the TCP port to get the connection */
  3812. static void
  3813. connect_to_energize (char *server_str, char *arg)
  3814. {
  3815.   struct Lisp_Process *proc;
  3816.   Lisp_Object lp;
  3817.   Lisp_Object fil;
  3818.   char *host;
  3819.   unsigned int port;
  3820.   long flags;
  3821.   int id1;
  3822.   int id2;
  3823.  
  3824.   if (CGetPortNumber (server_str, &host, &port))
  3825.     {
  3826.  
  3827.       lp = Fopen_network_stream_internal (build_string ("energize"),
  3828.                       Qnil,
  3829.                       build_string (host),
  3830.                       make_number (port));
  3831.       if (!NILP (lp))
  3832.     {
  3833.       int infd, outfd;
  3834.       /* Don't ask the user for confirmation when exiting Emacs */
  3835.       Fprocess_kill_without_query (lp, Qnil);
  3836.       proc = XPROCESS (lp);
  3837.       energize_connection = xnew (Editor);
  3838.       get_process_file_descriptors (proc, &infd, &outfd);
  3839.       energize_connection->conn =
  3840.         make_energize_connection (energize_connection, infd, outfd);
  3841.       energize_connection->proc = lp;
  3842.       energize_connection->binfo_hash = make_hashtable (10);
  3843.       energize_connection->image_table = 0;
  3844.       energize_connection->gc_save = Qnil;
  3845.       energize_connection->major = 0;
  3846.       energize_connection->minor = 0;
  3847.       peo = allocate_edit_options (10);
  3848.       request_serial_number = 0;
  3849.       global_reply_wait = 0;
  3850.  
  3851.       if ((flags = fcntl (energize_connection->conn->fdin, F_GETFL, 0))
  3852.           == -1)
  3853.         abort ();
  3854.  
  3855. #ifdef O_NONBLOCK
  3856.       if (fcntl (energize_connection->conn->fdin, F_SETFL,
  3857.              flags & ~O_NONBLOCK)
  3858.           == -1)
  3859. #else
  3860.       if (fcntl (energize_connection->conn->fdin, F_SETFL,
  3861.              flags & ~O_NDELAY)
  3862.           == -1)
  3863. #endif
  3864.         abort ();
  3865.  
  3866.       XSETSUBR (fil, &Shandle_energize_request);
  3867.       set_process_filter (lp, fil, 1);
  3868.  
  3869.       Venergize_kernel_busy = Qnil;
  3870.  
  3871.       id1 = 0;
  3872.       id2 = 0;
  3873.       if (arg)
  3874.         sscanf (arg, "%x,%x", &id1, &id2);
  3875.  
  3876.       Venergize_buffers_list = Qnil;
  3877.  
  3878.       setup_connection (energize_connection, id1, id2);
  3879.  
  3880.       Venergize_process = lp;
  3881.     }
  3882.       else
  3883.     error ("couldn't connect to " IDENTITY_CRISIS " server");
  3884.     }
  3885.   else
  3886.     error ("couldn't determine " IDENTITY_CRISIS " server port number");
  3887.  
  3888.  
  3889. #ifdef ENERGIZE_V2_HEADERS
  3890.   if (energize_connection->minor > 9)
  3891.     {
  3892.       close_energize_connection ();
  3893.       error ("This Emacs doesn't understand " IDENTITY_CRISIS " version 3.");
  3894.     }
  3895.  
  3896. #endif /* ENERGIZE_V2_HEADERS */
  3897.  
  3898. }
  3899.  
  3900.  
  3901. /* Close the connection to energize.
  3902.  * Kills all the energize related buffer */
  3903. static void
  3904. close_energize_connection ()
  3905. {
  3906.   Editor *ed = energize_connection;
  3907.  
  3908.   if (ed)
  3909.     /* make this function as paranoid as we can */
  3910.     {
  3911.       /* cleanup the busy state */
  3912.       show_all_menubars_busy (False);
  3913.       Venergize_kernel_busy = Qnil;
  3914.       /* destroy all pop_up boxes */
  3915.       lw_destroy_all_pop_ups ();
  3916.  
  3917.       if (ed->conn)
  3918.     DeleteConnection (ed->conn);
  3919.       ed->conn = 0;
  3920.  
  3921.       if (ed->binfo_hash)
  3922.     {
  3923.       int speccount = specpdl_depth ();
  3924.  
  3925.       /* we are flushing everything, so we just ignore any change
  3926.          hooks and don't make an effort to delete extents since they
  3927.          are all going away */
  3928.       specbind (Qenergize_buffer_modified_hook, Qnil);
  3929.       specbind (Qinhibit_quit, Qt);
  3930.       call0 (intern ("de-energize-all-buffers"));
  3931.       unbind_to (speccount, Qnil);
  3932.  
  3933.       free_hashtable (ed->binfo_hash);
  3934.       ed->binfo_hash = 0;
  3935.     }
  3936.  
  3937.       /* Do this after de-energize-all-buffers or frame sizes thrash. */
  3938.       debuggerpanel_sheet = 0;
  3939.       desired_debuggerpanel_exposed_p = 0;
  3940.  
  3941.       free_edit_options (peo);
  3942.  
  3943.       if (EQ (ed->proc, Qzero)) abort ();
  3944.  
  3945.       if (!NILP (ed->proc))
  3946.     Fdelete_process (ed->proc);
  3947.       ed->proc = Qnil;
  3948.  
  3949.       Venergize_buffers_list = Qnil;
  3950.  
  3951.       /* now kill buffers created to satisfy requests on old connection */
  3952.       xfree (ed);
  3953.     }
  3954.  
  3955.   /* mark as closed */
  3956.   energize_connection = 0;
  3957.   Venergize_process = Qnil;
  3958. }
  3959.  
  3960.  
  3961. DEFUN ("connect-to-energize-internal",
  3962.        Fconnect_to_energize_internal, Sconnect_to_energize_internal, 0, 2, 0,
  3963.        "Usage: (connect-to-energize-internal <server-name> <energizearg>)\n\
  3964. Energizearg representing two 32 bit Energize ids that will be passed\n\
  3965. to the Energize server when opening the Energize connection.\n\
  3966. Only one connection can be open at a time.")
  3967.  
  3968.   (server_name, energize_arg)
  3969.   Lisp_Object server_name, energize_arg;
  3970. {
  3971.   unsigned char *server;
  3972.   unsigned char *arg;
  3973.  
  3974.   if (!NILP (energize_arg))
  3975.     {
  3976.       CHECK_STRING (energize_arg, 1);
  3977.       arg = string_data (XSTRING (energize_arg));
  3978.     }
  3979.   else
  3980.     arg = 0;
  3981.  
  3982.   if (!NILP (server_name))
  3983.     {
  3984.       CHECK_STRING (server_name, 1);
  3985.       server = string_data (XSTRING (server_name));
  3986.     }
  3987.   else
  3988.     server = 0;
  3989.  
  3990.   /* since we are going ahead with this, make sure that we are
  3991.      really and truly disconnected first */
  3992.   Fclose_connection_to_energize ();
  3993.  
  3994.   connect_to_energize ((char *)server, (char *)arg);
  3995.   return Qnil;
  3996. }
  3997.  
  3998. DEFUN ("close-connection-to-energize", Fclose_connection_to_energize,
  3999.        Sclose_connection_to_energize, 0, 0, 0,
  4000.        "Close the open Energize connection, if any.")
  4001.      ()
  4002. {
  4003.   if (!energize_connection) return Qnil;
  4004.  
  4005.   close_energize_connection ();
  4006.   return Qnil;
  4007. }
  4008.  
  4009.  
  4010. /* Extents stuff; this used to be in extents.c */
  4011.  
  4012. static void
  4013. set_extent_flags (EXTENT extent, Energize_Extent_Data *ext)
  4014. {
  4015.   /* clear every flag */
  4016.   if (!EXTENT_LIVE_P (extent))
  4017.     return;
  4018.   extent_start_open_p (extent) = 0;
  4019.   extent_end_open_p (extent) = 1;
  4020.   extent_read_only_p (extent) = 0;
  4021.   extent_highlight_p (extent) = 0;
  4022.   extent_unique_p (extent) = 0;
  4023.   extent_duplicable_p (extent) = 0;
  4024.   extent_invisible_p (extent) = 0;
  4025.  
  4026.   set_extent_glyph (extent, 0, 0, GL_TEXT);
  4027.   set_extent_glyph (extent, 0, 1, GL_TEXT);
  4028.  
  4029.   if (ext)
  4030.     {
  4031.       ext->warn_modify = 0;
  4032.  
  4033.       switch (ext->extentType)
  4034.     {
  4035.     case CEAttribute:
  4036.       break;
  4037.  
  4038.     case CEAbbreviation:
  4039.       break;
  4040.  
  4041.     case CEWriteProtect:
  4042.       extent_read_only_p (extent) = 1;
  4043.       break;
  4044.  
  4045.     case CEGeneric:
  4046.       {
  4047.         GLYPH begin_glyph = 0;    /* always the class glyph */
  4048.         GLYPH end_glyph = 0;    /* always the instance glyph */
  4049.  
  4050.         /* if (ext->u.generic.gData->id)
  4051.              SET_EXTENT_FLAG (extent, EF_MENU);*/
  4052.  
  4053.         if (ext->u.generic.gData->glyph)
  4054.           end_glyph = ext->u.generic.gData->glyph;
  4055.         if (ext->u.generic.gData->cl && ext->u.generic.gData->cl->glyph)
  4056.           begin_glyph = ext->u.generic.gData->cl->glyph;
  4057.  
  4058. #if 0
  4059.         if (begin_glyph && end_glyph)
  4060.           {
  4061.         begin_glyph = end_glyph;
  4062.         end_glyph = 0;
  4063.           }
  4064. #endif
  4065.  
  4066.         if (begin_glyph)
  4067.           set_extent_glyph (extent, begin_glyph, 0, GL_TEXT);
  4068.         if (end_glyph)
  4069.           set_extent_glyph (extent, end_glyph, 1, GL_TEXT);
  4070.  
  4071.         if (ext->u.generic.gData->cl &&
  4072.         (ext->u.generic.gData->cl->flags & CCElectric))
  4073.           extent_highlight_p (extent) = 1;
  4074.         if (ext->u.generic.gData->cl &&
  4075.         (ext->u.generic.gData->cl->flags & CCWarnModified))
  4076.           ext->warn_modify = 1;
  4077. #if 0 /* #### some day (soon?)... */
  4078.         if (ext->u.generic.gData->cl &&
  4079.         (ext->u.generic.gData->cl->flags & CCColumn))
  4080.           SET_EXTENT_FLAG (extent, EF_COLUMN);
  4081. #endif
  4082.         extent_duplicable_p (extent) = 1;
  4083.         extent_unique_p (extent) = 1;
  4084.         break;
  4085.       }
  4086.  
  4087.     default:
  4088.       break;
  4089.     }
  4090.     }
  4091. }
  4092.  
  4093. extern Lisp_Object Fset_extent_face (Lisp_Object extent, Lisp_Object name);
  4094.  
  4095. static void
  4096. set_extent_attributes_index (EXTENT extent, Energize_Extent_Data *ext)
  4097. {
  4098.   int graphic_attributes;
  4099.  
  4100.   if (!ext)
  4101.     extent_face_id (extent) = -1;
  4102.   else
  4103.     {
  4104.       switch (ext->extentType)
  4105.     {
  4106.     case CEAttribute:
  4107.       graphic_attributes = ext->u.attr.attrValue;
  4108.       break;
  4109.  
  4110.     case CEGeneric:
  4111.       graphic_attributes = ext->u.generic.gData->attribute;
  4112.       break;
  4113.  
  4114.     case CEWriteProtect:
  4115.       /* this type has NO display attributes */
  4116.       extent_face_id (extent) = -1;
  4117.       return;
  4118.  
  4119.     default:
  4120.       graphic_attributes = GA_NO_CHANGE;
  4121.     }
  4122.  
  4123.       if (graphic_attributes >= GA_MAX)
  4124.     graphic_attributes = GA_NO_CHANGE;
  4125.  
  4126.       {
  4127.     /* The Venergize_attributes_mapping global is an alist of the form
  4128.        ( (<kernel-attribute-number> . <emacs-face-name> ) ... )
  4129.        */
  4130.     Lisp_Object face = Fcdr (Fassq (make_number (graphic_attributes),
  4131.                     Venergize_attributes_mapping));
  4132.     Lisp_Object e;
  4133.     XSETEXTENT (e, extent);
  4134.     if (NILP (face))
  4135.       message ("Unknown Energize attribute %d", graphic_attributes);
  4136.     else if (EQ (face, Qdefault))
  4137.       Fset_extent_face (e, Qnil);
  4138.     else
  4139.       Fset_extent_face (e, face);
  4140.       }
  4141.     }
  4142. }
  4143.  
  4144. void
  4145. restore_energize_extent_state (EXTENT extent)
  4146. {
  4147.   Energize_Extent_Data *ext = energize_extent_data (extent);
  4148.   if (!ext) return;
  4149.   set_extent_flags (extent, ext);
  4150.   set_extent_attributes_index (extent, ext);
  4151. }
  4152.  
  4153. DEFUN ("extent-to-generic-id", Fextent_to_generic_id, Sextent_to_generic_id,
  4154.        1, 1, 0, "Return Energize ID of buffer of EXTENT.")
  4155.      (extent_obj)
  4156.      Lisp_Object extent_obj;
  4157. {
  4158.   CHECK_EXTENT (extent_obj, 0);
  4159.   return word_to_lisp (energize_extent_data_id
  4160.                (energize_extent_data (XEXTENT (extent_obj))));
  4161. }
  4162.  
  4163.  
  4164.  
  4165. /* buffer modified routines */
  4166. static void
  4167. send_buffer_modification_state (Editor *editor, BufferInfo *binfo, int flag)
  4168. {
  4169.   Connection *conn = editor->conn;
  4170.   EId bufferId = binfo->id;
  4171.  
  4172.   if (conn)
  4173.     {
  4174.       int state = (flag)?(CMBufferSetModified):(CMBufferSetUnmodified);
  4175.       CWriteModifiedBufferHeader (conn, bufferId, state);
  4176.       CWriteRequestBuffer (conn);
  4177.     }
  4178. }
  4179.  
  4180. /* returns 1 if buffer is locked (non-editable),
  4181.    0 if it isn't (editable), and -1 if it can't tell
  4182.  */
  4183. static int
  4184. check_buffer_lock (Editor *editor, BufferInfo *binfo)
  4185. {
  4186.   Connection *conn = editor->conn;
  4187.   struct reply_wait rw;
  4188.  
  4189.   /* If permision already granted by kernel dont' ask again */
  4190.   if (binfo->editable)
  4191.     return 0;
  4192.  
  4193.   /* If can't ask say we do not know */
  4194.   if (!conn)
  4195.     return -1;
  4196.  
  4197.   /* Ask the kernel */
  4198.   CWriteModifiedBufferHeader (conn, binfo->id, CMBufferQueryLock);
  4199.   conn->header->serial = ++request_serial_number;
  4200.   CWriteRequestBuffer (conn);
  4201.  
  4202.   rw.serial = request_serial_number;
  4203.   rw.objectId = binfo->id;
  4204.   rw.status = -1;
  4205.  
  4206.   if (!wait_for_reply (&rw))
  4207.     return -1;
  4208.  
  4209.   if (rw.status == CMBufferLocked)
  4210.     {
  4211.       /* Buffer is locked by kernel so we cannot edit it */
  4212.       return 1;
  4213.     }
  4214.   else if (rw.status == CMBufferUnlocked)
  4215.     {
  4216.       /* Buffer is unlocked by kernel: edit permission granted! */
  4217.       binfo->editable = 1;
  4218.       return 0;
  4219.     }
  4220.   else
  4221.     {
  4222.       /* This should never happen */
  4223.       return -1;
  4224.     }
  4225. }
  4226.  
  4227.  
  4228. /* Ask the kernel if BUFFER is currently locked -- waits for answer */
  4229. static Lisp_Object
  4230. buffer_locked_p (Lisp_Object buffer)
  4231. {
  4232.   BufferInfo *binfo;
  4233.  
  4234.   if (!energize_connection)
  4235.     return Qnil;
  4236.  
  4237.   if (NILP (buffer))
  4238.     XSETBUFFER (buffer, current_buffer);
  4239.  
  4240.   CHECK_BUFFER (buffer, 0);
  4241.  
  4242.   binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
  4243.  
  4244.   if (!binfo)
  4245.     {
  4246.       /* Not an Energize buffer, return Qnil: can edit buffer */
  4247.       return Qnil;
  4248.     }
  4249.   else
  4250.     {
  4251.       /* Energize buffer, check if editable */
  4252.       return check_buffer_lock (energize_connection, binfo) == 0 ? Qnil : Qt;
  4253.     }
  4254. }
  4255.  
  4256.  
  4257.  
  4258. /* Called by map_extents function called by Fenergize_send_buffer_modified
  4259.  */
  4260. static int
  4261. notify_extent_modified (EXTENT extent, void *arg)
  4262. {
  4263.   /* arg is a binfo_and_state */
  4264.   binfo_and_state *bans = (binfo_and_state*)arg;
  4265.   Energize_Extent_Data *ext;
  4266.   BufferInfo *binfo = bans->binfo;
  4267.   Connection *conn = binfo->editor->conn;
  4268.   EId *extent_id;
  4269.   Lisp_Object extent_obj;
  4270.  
  4271.   XSETEXTENT (extent_obj, extent);
  4272.   if ((ext = extent_to_data (extent_obj))
  4273.       && ext->warn_modify
  4274.       && ext->extentType == CEGeneric
  4275.       && ext->u.generic.gData
  4276.       && ext->u.generic.gData->cl
  4277.       && (ext->u.generic.gData->cl->flags & CCWarnModified)
  4278.       && ext->u.generic.gData->modified_state != bans->state)
  4279.     {
  4280.       if (bans->tell_energize)
  4281.     {
  4282.       CWriteModifiedExtentsHeader (conn, binfo->id, bans->state, 1);
  4283.       extent_id = CPut (conn, EId);
  4284.       *extent_id = ext->id;
  4285.       CWriteLength (conn);
  4286.       CWriteRequestBuffer (conn);
  4287.     }
  4288.       ext->u.generic.gData->modified_state = bans->state;
  4289.     }
  4290.   return 0;
  4291. }
  4292.  
  4293. static int
  4294. ceiwme_lower_mf (EXTENT e, void *arg)
  4295. {
  4296.   Lisp_Object extent;
  4297.   Energize_Extent_Data *ext;
  4298.   XSETEXTENT (extent, e);
  4299.   ext = extent_to_data (extent);
  4300.   if (ext && ext->warn_modify)
  4301.     *((EXTENT *) arg) = e;
  4302.   return 0;
  4303. }
  4304.  
  4305. static int
  4306. ceiwme_upper_mf (EXTENT e, void *arg)
  4307. {
  4308.   Lisp_Object extent;
  4309.   Energize_Extent_Data *ext;
  4310.   XSETEXTENT (extent, e);
  4311.   ext = extent_to_data (extent);
  4312.   if (ext && ext->warn_modify)
  4313.     {
  4314.       *((EXTENT *) arg) = e;
  4315.       return 1;
  4316.     }
  4317.   else
  4318.     return 0;
  4319. }
  4320.  
  4321. static void
  4322. coerce_endpoints_to_be_inside_warn_on_modify_extents (Bufpos *from_ptr,
  4323.                               Bufpos *to_ptr,
  4324.                               struct buffer *b)
  4325. {
  4326.   EXTENT lower_extent = 0;
  4327.   EXTENT upper_extent = 0;
  4328.   Bufpos lower_bound = *from_ptr;
  4329.   Bufpos upper_bound = *to_ptr;
  4330.   Lisp_Object tmp;
  4331.  
  4332.   /* make sure that from <= to */
  4333.   {
  4334.     Bufpos tmp_int = max (lower_bound, upper_bound);
  4335.     *from_ptr = lower_bound = min (lower_bound, upper_bound);
  4336.     *to_ptr = upper_bound = tmp_int;
  4337.   }
  4338.  
  4339.   if (!BUFFER_NOTIFY_BACKGROUND_BIT_SET_P (b))
  4340.     return;
  4341.  
  4342.   map_extents (BUF_BEG (b), lower_bound, ceiwme_lower_mf,
  4343.            (void *) &lower_extent, make_buffer (b), 0, ME_END_CLOSED);
  4344.   if (!lower_extent)
  4345.     {
  4346.       lower_bound = BUF_BEG (b);
  4347.       map_extents (upper_bound, BUF_Z (b), ceiwme_upper_mf,
  4348.            (void *) &upper_extent, make_buffer (b), 0, ME_END_CLOSED);
  4349.       if (!upper_extent)
  4350.     upper_bound = BUF_Z (b);
  4351.       else
  4352.     {
  4353.       Bufpos xstart;
  4354.       XSETEXTENT (tmp, upper_extent);
  4355.       xstart = XINT (Fextent_start_position (tmp));
  4356.       upper_bound = max (upper_bound, xstart);
  4357.     }
  4358.     }
  4359.   /* I forget why, but if we found an lower bound, we don't need to find
  4360.      an upper bound */
  4361.   else
  4362.     {
  4363.       Bufpos xstart;
  4364.       XSETEXTENT (tmp, lower_extent);
  4365.       xstart = XINT (Fextent_start_position (tmp));
  4366.       lower_bound = min (lower_bound, xstart);
  4367.     }
  4368.  
  4369.   *from_ptr = lower_bound;
  4370.   *to_ptr = upper_bound;
  4371.   return;
  4372. }
  4373.  
  4374. static void
  4375. mark_all_extents_as_unmodified (BufferInfo *binfo)
  4376. {
  4377.   binfo_and_state bans;
  4378.   bans.binfo = binfo;
  4379.   bans.state = FALSE;
  4380.   bans.tell_energize = FALSE;
  4381.  
  4382.   map_extents (BUF_BEG (XBUFFER (binfo->emacs_buffer)),
  4383.            BUF_Z (XBUFFER (binfo->emacs_buffer)),
  4384.            notify_extent_modified, &bans,
  4385.            binfo->emacs_buffer, 0, ME_END_CLOSED);
  4386. }
  4387.  
  4388. /* Send the BufferModified events for the current buffer.
  4389.  * Handles both global buffer modified and extents modified. */
  4390. DEFUN ("energize-send-buffer-modified", Fenergize_send_buffer_modified,
  4391.        Senergize_send_buffer_modified,
  4392.        3, 3, 0,
  4393.        "Send a BufferModified request for the current buffer.")
  4394.      (state, from, to)
  4395.      Lisp_Object state, from, to; /* dont use ANSI arglists in DEFUNs */
  4396. {
  4397.   int modifiedp = NILP (state)? 0 : 1;
  4398.   Lisp_Object buffer;
  4399.   BufferInfo *binfo;
  4400.   Bufpos from_int = XINT (from);
  4401.   Bufpos to_int = XINT (to);
  4402.  
  4403.   if (!energize_connection || !energize_connection->conn) return Qnil;
  4404.  
  4405.   XSETBUFFER (buffer, current_buffer);
  4406.  
  4407.   Fenergize_barf_if_buffer_locked ();
  4408.  
  4409.   if (binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection))
  4410.     {
  4411.       /* now make sure that from and to
  4412.      are inside some warn_on_modify extents somewhere */
  4413.       coerce_endpoints_to_be_inside_warn_on_modify_extents
  4414.     (&from_int, &to_int, current_buffer);
  4415.       XSETINT (from, from_int);
  4416.       XSETINT (to, to_int);
  4417.  
  4418.       if (binfo->modified_state != modifiedp)
  4419.     {
  4420.       send_buffer_modification_state (energize_connection, binfo,
  4421.                       modifiedp);
  4422.       binfo->modified_state = modifiedp;
  4423.     }
  4424. #ifndef ENERGIZE_V2_HEADERS
  4425.       if (!(binfo->flags & CBFileYourself))
  4426. #endif
  4427.     {
  4428.       if (modifiedp)
  4429.         {
  4430.           binfo_and_state bans;
  4431.           bans.binfo = binfo;
  4432.           bans.state = 1;
  4433.           bans.tell_energize = 1;
  4434.           map_extents (XINT (from), XINT (to),
  4435.                notify_extent_modified, &bans,
  4436.                binfo->emacs_buffer, 0,
  4437.                ME_END_CLOSED);
  4438.         }
  4439.       else
  4440.         mark_all_extents_as_unmodified (binfo);
  4441.     }
  4442.     }
  4443.   return Qnil;
  4444. }
  4445.  
  4446. DEFUN ("energize-barf-if-buffer-locked", Fenergize_barf_if_buffer_locked,
  4447.        Senergize_barf_if_buffer_locked, 0, 0, 0,
  4448.        "Error if the buffer is locked.")
  4449.      ()
  4450. {
  4451.   Lisp_Object buffer;
  4452.   XSETBUFFER (buffer, current_buffer);
  4453.  
  4454.   if (!energize_connection || !energize_connection->conn)
  4455.     return Qnil;
  4456.  
  4457.   while (!NILP (buffer_locked_p (buffer)))
  4458.     {
  4459.       notify_delayed_requests ();
  4460.       Fsignal (Qbuffer_locked_by_energize, (Fcons (buffer, Qnil)));
  4461.     }
  4462.   return Qnil;
  4463. }
  4464.  
  4465.  
  4466. DEFUN ("energize-send-region", Fenergize_send_region,
  4467.        Senergize_send_region,
  4468.        2, 2, 0,
  4469.        "Send region as user input")
  4470.      (start, end)
  4471.      Lisp_Object start, end;
  4472. {
  4473.   BufferInfo *binfo;
  4474.   Lisp_Object b;
  4475.   CEditorRequest *req;
  4476.  
  4477.   if (!energize_connection || !energize_connection->conn)
  4478.     error ("Not connected to " IDENTITY_CRISIS);
  4479.  
  4480.   XSETBUFFER (b, current_buffer);
  4481.   if (binfo = get_buffer_info_for_emacs_buffer (b, energize_connection))
  4482.     {
  4483.       Bufpos st, en;
  4484.       Bufpos ceil;
  4485.  
  4486.       get_bufrange (current_buffer, start, end, &st, &en);
  4487.  
  4488.       do
  4489.     {
  4490.       ceil = BUF_CEILING_OF (current_buffer, st);
  4491.  
  4492.       req = CWriteEditorRequest (energize_connection->conn,
  4493.                      UserTypedSomethingRType);
  4494.       req->usertypedsomething.bufferId = binfo->id;
  4495.       CWriteVstringLen
  4496.         (energize_connection->conn,
  4497.          (char *) BUF_BYTE_ADDRESS (current_buffer, st), ceil - st);
  4498.       CWriteLength (energize_connection->conn);
  4499.       CWriteRequestBuffer (energize_connection->conn);
  4500.       st = ceil;
  4501.     } while (st < en);
  4502.       return Qnil;
  4503.     }
  4504.   return Qnil;
  4505. }
  4506.  
  4507. DEFUN ("connected-to-energize-p", Fconnected_to_energize_p,
  4508.        Sconnected_to_energize_p,
  4509.        0, 0, 0,
  4510. "Return nil if no connection to Energize.")
  4511.      ()
  4512. {
  4513.   if (!energize_connection ||
  4514.       !energize_connection->conn ||
  4515.       !energize_connection->binfo_hash ||
  4516.       !PROCESSP (energize_connection->proc))
  4517.     return Qnil;
  4518.   else
  4519.     return Qt;
  4520. }
  4521.  
  4522. DEFUN ("energize-user-input-buffer-mark", Fenergize_user_input_buffer_mark,
  4523.        Senergize_user_input_buffer_mark, 0, 1, 0,
  4524.        "Return the mark associated to the given Energize buffer.")
  4525.      (buffer)
  4526.      Lisp_Object buffer;
  4527. {
  4528.   BufferInfo *binfo;
  4529.  
  4530.   XSETBUFFER (buffer, decode_buffer (buffer, 0));
  4531.   if (!energize_connection) return Qnil;
  4532.   if ((binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
  4533.     return binfo->output_mark;
  4534.   else
  4535.     return Qnil;
  4536. }
  4537.  
  4538. Lisp_Object
  4539. energize_get_buffer_process (Lisp_Object buf)
  4540. {
  4541.   BufferInfo *binfo;
  4542.  
  4543.   if (!BUFFERP (buf)) return Qnil;
  4544.   if (!energize_connection) return Qnil;
  4545.   binfo = get_buffer_info_for_emacs_buffer (buf, energize_connection);
  4546.   if (!binfo) return Qnil;
  4547.   if (! binfo->buffer_type) return Qnil;
  4548.   if (!strcmp (binfo->buffer_type, "energize-debugger-buffer") ||
  4549.       !strcmp (binfo->buffer_type, "energize-log-file-buffer"))
  4550.     return Venergize_process;
  4551.   return Qnil;
  4552. }
  4553.  
  4554.  
  4555. static int
  4556. get_energize_connection_and_buffer_id (Lisp_Object buffer, void **conn_ptr,
  4557.                        long *buffer_id_ptr)
  4558. {
  4559.   BufferInfo *binfo;
  4560.  
  4561.   if (!energize_connection || !energize_connection->conn) return 0;
  4562.  
  4563.   binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
  4564.  
  4565.   *conn_ptr = (void *) energize_connection->conn;
  4566.   *buffer_id_ptr = (long) binfo ? binfo->id : 0;
  4567.   return 1;
  4568. }
  4569.  
  4570. static int
  4571. get_energize_connection_and_current_buffer_id (void **conn_ptr,
  4572.                            long *buffer_id_ptr)
  4573. {
  4574.   Lisp_Object lisp_buffer;
  4575.   XSETBUFFER (lisp_buffer, current_buffer);
  4576.  
  4577.   return get_energize_connection_and_buffer_id (lisp_buffer, conn_ptr,
  4578.                         buffer_id_ptr);
  4579. }
  4580.  
  4581. int *
  4582. get_psheets_for_buffer (Lisp_Object buffer, int *count_ptr)
  4583. {
  4584.   BufferInfo *binfo;
  4585.  
  4586.   if (!energize_connection || !energize_connection->conn) return 0;
  4587.  
  4588.   binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
  4589.   if (!binfo) return 0;
  4590.  
  4591.   if (count_ptr) *count_ptr = binfo->n_p_sheets;
  4592.   return binfo->p_sheet_ids;
  4593. }
  4594.  
  4595. void
  4596. notify_energize_sheet_hidden (EId id)
  4597. {
  4598.   EId buffer_id = buffer_id_of_sheet (id);
  4599.   if (!buffer_id)
  4600.     return;
  4601.  
  4602.   if (buffer_id && energize_connection && energize_connection->conn)
  4603.     {
  4604.       CWriteSheetRequest (energize_connection->conn,
  4605.               CSHide, id, buffer_id, "");
  4606.       CWriteRequestBuffer (energize_connection->conn);
  4607.     }
  4608. }
  4609.  
  4610. DEFUN ("energize-query-buffer", Fenergize_query_buffer,
  4611.        Senergize_query_buffer, 1, 2, 0,
  4612.        "Ask Energize to create a buffer containing the file filename.\n\
  4613. Returns the buffer or NIL if Energize cannot create the buffer.\n\
  4614. If second argument just-ask is T, just ask if Energize\n\
  4615. already knows about the file and returns T if yes, NIL otherwise.")
  4616.      (filename, just_ask)
  4617.      Lisp_Object filename, just_ask;
  4618. {
  4619.   struct Lisp_String *filename_str;
  4620.   CEditorRequest *creq;
  4621.   char *dir_sep;
  4622.   struct reply_wait rw;
  4623.  
  4624.   if (!energize_connection || !energize_connection->conn)
  4625.     return Qnil;
  4626.  
  4627.   filename = Fexpand_file_name (filename, Qnil);
  4628.   filename_str = XSTRING (filename);
  4629.  
  4630.   dir_sep = (char *) strrchr ((char *) string_data (filename_str), '/');
  4631.  
  4632.   creq = CWriteEditorRequest (energize_connection->conn, QueryBufferRType);
  4633.   creq->head.data = !NILP (just_ask);
  4634.   creq->head.serial = ++request_serial_number;
  4635.   CWriteVstringLen (energize_connection->conn, (char *) string_data (filename_str),
  4636.             (dir_sep)? (dir_sep - (char *) string_data (filename_str)): 0);
  4637.   CWriteVstringLen (energize_connection->conn,
  4638.             (char *) string_data (filename_str), string_length (filename_str));
  4639.   CWriteLength (energize_connection->conn);
  4640.   CWriteRequestBuffer (energize_connection->conn);
  4641.  
  4642.   rw.serial = request_serial_number;
  4643.   rw.objectId = 0;
  4644.  
  4645.   if (!wait_for_reply (&rw))
  4646.     return Qnil;
  4647.  
  4648.   if (rw.status)
  4649.     {
  4650.       if (rw.objectId)
  4651.     {
  4652.       BufferInfo* binfo = get_buffer_info_for_id (rw.objectId,
  4653.                               energize_connection);
  4654.       return binfo ? binfo->emacs_buffer : Qt;
  4655.     }
  4656.       else
  4657.     return Qt;
  4658.     }
  4659.   else
  4660.     return Qnil;
  4661. }
  4662.  
  4663.  
  4664. DEFUN ("energize-protocol-level", Fenergize_protocol_level,
  4665.        Senergize_protocol_level, 0, 0, 0,
  4666.        "Return the Energize protocol level.")
  4667.      ()
  4668. {
  4669.   return
  4670.     energize_connection
  4671.       ? Fcons (make_number (energize_connection->major),
  4672.            make_number (energize_connection->minor))
  4673.     : Qnil;
  4674. }
  4675.  
  4676.  
  4677. DEFUN ("energize-psheets-visible-p", Fenergize_psheets_visible_p,
  4678.        Senergize_psheets_visible_p, 0, 1, 0,
  4679.        "Whether the (optional) frame currently has open psheets.")
  4680.      (frame)
  4681.      Lisp_Object frame;
  4682. {
  4683.   if (NILP (frame))
  4684.     XSETFRAME (frame, XFRAME(Fselected_frame(Qnil)));
  4685.   CHECK_FRAME (frame, 0);
  4686.   if (FRAME_X_CURRENT_PSHEETS (XFRAME (frame)))
  4687.     return Qt;
  4688.   return Qnil;
  4689. }
  4690.  
  4691. DEFUN ("energize-buffer-has-psheets-p", Fenergize_buffer_has_psheets_p,
  4692.        Senergize_buffer_has_psheets_p, 0, 1, 0,
  4693.        "Whether the buffer has psheets associated with it.")
  4694.      (buf)
  4695.      Lisp_Object buf;
  4696. {
  4697.   int count;
  4698.   if (NILP (buf))
  4699.     buf = Fcurrent_buffer ();
  4700.   CHECK_BUFFER (buf, 0);
  4701.   if (get_psheets_for_buffer (buf, &count))
  4702.     return Qt;
  4703.   return Qnil;
  4704. }
  4705.  
  4706.  
  4707. void
  4708. make_psheets_desired (struct frame *f, Lisp_Object buffer)
  4709. {
  4710.   int count;
  4711.   int *psheets;
  4712.  
  4713.   if (NILP (buffer) || !(psheets = get_psheets_for_buffer (buffer, &count)))
  4714.     {
  4715.       FRAME_X_DESIRED_PSHEETS (f) = 0;
  4716.       FRAME_X_DESIRED_PSHEET_COUNT (f) = 0;
  4717.       FRAME_X_DESIRED_PSHEET_BUFFER (f) = Qnil;
  4718.     }
  4719.   else
  4720.     {
  4721.       /* Do not show the debugger panel in this function.  The
  4722.        * debugger panel should never be listed in the visible psheets. */
  4723.       extern int debuggerpanel_sheet;
  4724.       
  4725.       if (count == 1 && psheets [0] == debuggerpanel_sheet)
  4726.     return;
  4727.  
  4728.       FRAME_X_DESIRED_PSHEETS (f) = psheets;
  4729.       FRAME_X_DESIRED_PSHEET_COUNT (f) = count;
  4730.       FRAME_X_DESIRED_PSHEET_BUFFER (f) = buffer;
  4731.     }
  4732.  
  4733.   /* Garbage the frame so that the sheets get recomputed right away and not
  4734.      the next time some display change happens.  Possibly redisplay should
  4735.      notice this on its own without the garbaged flag.  But once redisplay
  4736.      gets smarter about such things, all garbagers should be revisited.
  4737.    */
  4738.   MARK_FRAME_CHANGED (f);
  4739. }
  4740.  
  4741. Lisp_Object
  4742. desired_psheet_buffer (struct frame *f)
  4743. {
  4744.   if (FRAME_IS_X (f))
  4745.   return FRAME_X_DESIRED_PSHEET_BUFFER (f);
  4746.   else
  4747.     return Qnil;
  4748. }
  4749.  
  4750. /* This function is invoked when the user clicks on the "sheet" button.
  4751.  */
  4752. DEFUN ("energize-toggle-psheet", Fenergize_toggle_psheet,
  4753.        Senergize_toggle_psheet, 0, 0, "",
  4754.        "")
  4755.      ()
  4756. {
  4757.   struct frame *frame = XFRAME(Fselected_frame(Qnil));
  4758.   Lisp_Object buffer = Fwindow_buffer (Fselected_window (Qnil));
  4759.   if (EQ (buffer, desired_psheet_buffer (frame)))
  4760.     make_psheets_desired (frame, Qnil);
  4761.   else
  4762.     make_psheets_desired (frame, buffer);
  4763.   return Qnil;
  4764. }
  4765.  
  4766.  
  4767. static void energize_show_menubar_of_buffer (Lisp_Object frame,
  4768.                          Lisp_Object buffer,
  4769.                          Lisp_Object psheets_too);
  4770.  
  4771. /* This is called when a buffer becomes visible in some window.
  4772.  
  4773.    Show the menubar associated with this buffer, and show the psheets as
  4774.    well if this buffer is the last buffer whose psheets were visible in
  4775.    this frame.
  4776.  */
  4777. void
  4778. energize_buffer_shown_hook (struct window *window)
  4779. {
  4780.   struct frame* frame = XFRAME (window->frame);
  4781.   Lisp_Object buffer = window->buffer;
  4782.   Lisp_Object pbuf;
  4783.  
  4784.   if (! FRAME_IS_X (frame)) return;
  4785.   pbuf = desired_psheet_buffer (frame);
  4786.  
  4787.   if (!MINI_WINDOW_P (window))
  4788.     energize_show_menubar_of_buffer (window->frame, buffer,
  4789.                      (EQ (buffer, pbuf) ? Qt : Qnil));
  4790. }
  4791.  
  4792.  
  4793. static int
  4794. find_buffer_in_different_window (window, buffer, not_in)
  4795.      struct window* window;
  4796.      Lisp_Object buffer;
  4797.      struct window* not_in;
  4798. {
  4799.   Lisp_Object child;
  4800.   if (!NILP (window->buffer))
  4801.     {
  4802.       /* a leaf window */
  4803.       return (EQ (window->buffer, buffer) && (window != not_in));
  4804.     }
  4805.   else
  4806.     {
  4807.       /* a non leaf window, visit either the hchild or the vchild */
  4808.       for (child = !NILP (window->vchild) ? window->vchild : window->hchild;
  4809.        !NILP (child);
  4810.        child = XWINDOW (child)->next)
  4811.     {
  4812.       if (find_buffer_in_different_window (XWINDOW (child), buffer,
  4813.                            not_in))
  4814.         return 1;
  4815.     }
  4816.       return 0;
  4817.     }
  4818. }
  4819.  
  4820. /* returns 1 if the buffer is only visible in window on frame f */
  4821. static int
  4822. buffer_only_visible_in_this_window_p (Lisp_Object buffer, 
  4823.                       struct frame* f, 
  4824.                       struct window* window)
  4825. {
  4826.   return !find_buffer_in_different_window (XWINDOW (f->root_window), buffer,
  4827.                        window);
  4828. }
  4829.  
  4830. /* This is called just before a buffer which is visible becomes invisible,
  4831.    either because some other buffer is about to be made visible in its window,
  4832.    or because that window is being deleted.
  4833.  
  4834.    If this buffer's psheets are visible, hide them.
  4835.  */
  4836. void
  4837. energize_buffer_hidden_hook (struct window *window)
  4838. {
  4839.   struct frame *f = XFRAME (window->frame);
  4840.  
  4841.   if (! FRAME_IS_X (f)) return;
  4842.  
  4843.   /* hides the p_sheet if we are changing the buffer of the
  4844.    * selected window of the frame and the p_sheet where displayed */
  4845.   if (EQ (window->buffer, desired_psheet_buffer (f))
  4846.       && buffer_only_visible_in_this_window_p (window->buffer, f, window))
  4847.     make_psheets_desired (f, Qnil);
  4848. }
  4849.  
  4850.  
  4851. /* This is called just before the selected window is no longer the selected
  4852.    window because some other window is being selected.  The given window is
  4853.    not being deleted, it is merely no longer the selected one.
  4854.  
  4855.    This doesn't do anything right now.
  4856.  */
  4857. void
  4858. energize_window_deselected_hook (struct window *window)
  4859. {
  4860. }
  4861.  
  4862.  
  4863. /* This is called just after a window has been selected.
  4864.  
  4865.    Show the menubar associated with this buffer; leave the psheets as
  4866.    they are.
  4867.  */
  4868. void
  4869. energize_window_selected_hook (struct window *window)
  4870. {
  4871.   struct frame* frame = XFRAME (window->frame);
  4872.   Lisp_Object buffer = window->buffer;
  4873.  
  4874.   if (FRAME_IS_X (frame) && !MINI_WINDOW_P (window))
  4875.     energize_show_menubar_of_buffer (window->frame, buffer, Qnil);
  4876. }
  4877.  
  4878.  
  4879.  
  4880. int current_debuggerpanel_exposed_p;
  4881. int desired_debuggerpanel_exposed_p;
  4882. int debuggerpanel_sheet;
  4883.  
  4884. static void
  4885. energize_show_menubar_of_buffer (Lisp_Object frame,
  4886.                  Lisp_Object buffer,
  4887.                  Lisp_Object psheets_too)
  4888. {
  4889.   struct frame *f;
  4890.   
  4891.   if (NILP (frame))
  4892.     f = XFRAME (Fselected_frame (Qnil));
  4893.   else {
  4894.     CHECK_FRAME (frame, 0);
  4895.     f = XFRAME (frame);
  4896.   }
  4897.  
  4898.   if (! FRAME_IS_X (f)) error ("not an X frame");
  4899.  
  4900.   if (! NILP (psheets_too))
  4901.     {
  4902.       Lisp_Object buffer;
  4903.       XSETBUFFER (buffer, current_buffer);
  4904.       make_psheets_desired (f, buffer);
  4905.     }
  4906. }
  4907.  
  4908.  
  4909. /* edit-mode dialog box
  4910.    This stuff really sucks
  4911.  */
  4912.  
  4913. static struct editmode {
  4914.   int ok, external, view, edit, window, split;
  4915.   char *other;
  4916. } editmode;
  4917.  
  4918. static void
  4919. edit_mode_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
  4920. {
  4921.   widget_value *data;
  4922.   char *name = (char *) client_data;
  4923.  
  4924.   if ((int) client_data == -1) name = "cancel";    /* WM_DELETE_WINDOW */
  4925.  
  4926.   if (!strcmp (XtName (widget), "otherText")) /* screw it */
  4927.     ;
  4928.   else if (!strcmp (name, "externalBox"))
  4929.     {
  4930.       /* make the text slot be active only if "other" is selected */
  4931.       data = malloc_widget_value ();
  4932.       data->name = "externalOther";
  4933.       if (! lw_get_some_values (id, data)) abort ();
  4934.       data->enabled = data->selected;
  4935.       data->name = "otherText";
  4936.       lw_modify_all_widgets (id, data, True);
  4937.       free_widget_value (data);
  4938.     }
  4939.   else if (!strcmp (name, "cancel"))
  4940.     {
  4941.       editmode.ok = -1;
  4942.       lw_destroy_all_widgets (id);
  4943.     }
  4944.   else if (!strcmp (name, "help"))
  4945.     {
  4946.       Lisp_Object v = Fmake_vector (make_number (3), Qt);
  4947.       vector_data (XVECTOR (v)) [0] = build_string ("ok");
  4948.       vector_data (XVECTOR (v)) [1] = list1 (Qignore);
  4949.       Fpopup_dialog_box (list2 (build_string ("dbx_editmode_help"), v));
  4950.     }
  4951.   else if (!strcmp (name, "ok"))
  4952.     {
  4953.       editmode.ok = 1;
  4954.       data = malloc_widget_value ();
  4955.       data->name = "externalEmacs";
  4956.       if (! lw_get_some_values (id, data)) abort ();
  4957.       if (data->selected) editmode.external = 0;
  4958.       data->name = "externalViXterm";
  4959.       if (! lw_get_some_values (id, data)) abort ();
  4960.       if (data->selected) editmode.external = 1;
  4961.       data->name = "externalViCmdtool";
  4962.       if (! lw_get_some_values (id, data)) abort ();
  4963.       if (data->selected) editmode.external = 2;
  4964.       data->name = "externalOther";
  4965.       if (! lw_get_some_values (id, data)) abort ();
  4966.       if (data->selected) editmode.external = 3;
  4967.       data->name = "otherText";
  4968.       if (! lw_get_some_values (id, data)) abort ();
  4969.       editmode.other = data->value;
  4970.  
  4971.       data->name = "emacsView";
  4972.       if (! lw_get_some_values (id, data)) abort ();
  4973.       if (data->selected) editmode.view = 0;
  4974.       data->name = "viView";
  4975.       if (! lw_get_some_values (id, data)) abort ();
  4976.       if (data->selected) editmode.view = 1;
  4977.       data->name = "lessView";
  4978.       if (! lw_get_some_values (id, data)) abort ();
  4979.       if (data->selected) editmode.view = 2;
  4980.  
  4981.       data->name = "editEmacs";
  4982.       if (! lw_get_some_values (id, data)) abort ();
  4983.       if (data->selected) editmode.edit = 0;
  4984.       data->name = "editVi";
  4985.       if (! lw_get_some_values (id, data)) abort ();
  4986.       if (data->selected) editmode.edit = 1;
  4987.  
  4988.       data->name = "windowOne";
  4989.       if (! lw_get_some_values (id, data)) abort ();
  4990.       if (data->selected) editmode.window = 0;
  4991.       data->name = "windowSeveral";
  4992.       if (! lw_get_some_values (id, data)) abort ();
  4993.       if (data->selected) editmode.window = 1;
  4994.       data->name = "windowMany";
  4995.       if (! lw_get_some_values (id, data)) abort ();
  4996.       if (data->selected) editmode.window = 2;
  4997.  
  4998.       data->name = "splitScreens";
  4999.       if (! lw_get_some_values (id, data)) abort ();
  5000.       editmode.split = !!data->selected;
  5001.  
  5002.       free_widget_value (data);
  5003.       lw_destroy_all_widgets (id);
  5004.     }
  5005.   else
  5006.     {
  5007.       abort ();
  5008.     }
  5009. }
  5010.  
  5011. static int
  5012. editmode_done (void *arg)
  5013. {
  5014.   return (editmode.ok != 0);
  5015. }
  5016.  
  5017. extern LWLIB_ID new_lwlib_id (void);
  5018.  
  5019. DEFUN ("energize-edit-mode-prompt", Fenergize_edit_mode_prompt,
  5020.        Senergize_edit_mode_prompt, 6, 6, 0, "")
  5021.      (external, edit_mode, view_mode, other_text, window, split)
  5022.      Lisp_Object external, edit_mode, view_mode, other_text, window, split;
  5023. {
  5024.   int dbox_id;
  5025.   struct frame *f = XFRAME(Fselected_frame(Qnil));
  5026.   widget_value *data;
  5027.   Widget parent, dbox;
  5028.  
  5029.   if (!FRAME_IS_X (f)) error ("not an X frame");
  5030.   parent = FRAME_X_SHELL_WIDGET (f);
  5031.  
  5032.   CHECK_INT (external, 0);
  5033.   CHECK_INT (edit_mode, 0);
  5034.   CHECK_INT (view_mode, 0);
  5035.   CHECK_INT (window, 0);
  5036.   CHECK_INT (split, 0);
  5037.   CHECK_STRING (other_text, 0);
  5038.  
  5039.   editmode.ok = 0;
  5040.   editmode.external = XINT (external);
  5041.   editmode.view = XINT (view_mode);
  5042.   editmode.edit = XINT (edit_mode);
  5043.   editmode.window = XINT (window);
  5044.   editmode.split = XINT (split);
  5045.   editmode.other = 0;
  5046.  
  5047.   data = malloc_widget_value ();
  5048.   data->name = "editmode";
  5049.   data->value = "editmode";
  5050.   data->enabled = 1;
  5051.  
  5052.   dbox_id = new_lwlib_id ();
  5053.   dbox = lw_create_widget ("editmode", "editmode", dbox_id, data, parent,
  5054.                1, 0, edit_mode_callback, 0);
  5055.   data->value = 0;
  5056.  
  5057.   data->name = "button1"; data->call_data = data->value = "ok";
  5058.   lw_modify_all_widgets (dbox_id, data, True);
  5059.   data->name = "button2"; data->call_data = data->value = "cancel";
  5060.   lw_modify_all_widgets (dbox_id, data, True);
  5061.   data->name = "button3"; data->call_data = data->value = "help";
  5062.   lw_modify_all_widgets (dbox_id, data, True);
  5063.   data->name = data->call_data = "externalBox";
  5064.   lw_modify_all_widgets (dbox_id, data, True);
  5065.   data->name = "otherText"; data->call_data = "otherText";
  5066.   lw_modify_all_widgets (dbox_id, data, True);
  5067.   data->name = "message"; data->value = "editmode";
  5068.   lw_modify_all_widgets (dbox_id, data, True);
  5069.  
  5070.   data->selected = 1;
  5071.   switch (editmode.external)
  5072.     {
  5073.     case 0: data->name = "externalEmacs"; break;
  5074.     case 1: data->name = "externalViXterm"; break;
  5075.     case 2: data->name = "externalViCmdtool"; break;
  5076.     case 3: data->name = "externalOther"; break;
  5077.     default: abort ();
  5078.     }
  5079.   lw_modify_all_widgets (dbox_id, data, True);
  5080.   switch (editmode.view)
  5081.     {
  5082.     case 0: data->name = "emacsView"; break;
  5083.     case 1: data->name = "viView"; break;
  5084.     case 2: data->name = "lessView"; break;
  5085.     default: abort ();
  5086.     }
  5087.   lw_modify_all_widgets (dbox_id, data, True);
  5088.   switch (editmode.edit)
  5089.     {
  5090.     case 0: data->name = "editEmacs"; break;
  5091.     case 1: data->name = "editVi"; break;
  5092.     default: abort ();
  5093.     }
  5094.   lw_modify_all_widgets (dbox_id, data, True);
  5095.   switch (editmode.window)
  5096.     {
  5097.     case 0: data->name = "windowOne"; break;
  5098.     case 1: data->name = "windowSeveral"; break;
  5099.     case 2: data->name = "windowMany"; break;
  5100.     default: abort ();
  5101.     }
  5102.   lw_modify_all_widgets (dbox_id, data, True);
  5103.  
  5104.   data->name = "otherText";
  5105.   data->selected = 0;
  5106.   data->value = (char *) string_data (XSTRING (other_text));
  5107.   data->enabled = (editmode.external == 3);
  5108.   lw_modify_all_widgets (dbox_id, data, True);
  5109.  
  5110.   data->name = "splitScreens";
  5111.   data->enabled = 1;
  5112.   data->selected = editmode.split;
  5113.   data->value = 0;
  5114.   lw_modify_all_widgets (dbox_id, data, True);
  5115.  
  5116.   free_widget_value (data);
  5117.  
  5118.   lw_pop_up_all_widgets (dbox_id);
  5119.  
  5120.   wait_delaying_user_input (editmode_done, 0);
  5121.  
  5122.   if (editmode.ok == -1)
  5123.     return Fcons (external,
  5124.           list5 (edit_mode, view_mode, other_text, window, split));
  5125.   else if (editmode.ok == 1)
  5126.     return Fcons (make_number (editmode.external),
  5127.           list5 (make_number (editmode.view),
  5128.              make_number (editmode.edit),
  5129.              build_string (editmode.other ? editmode.other : ""),
  5130.              make_number (editmode.window),
  5131.              make_number (editmode.split)));
  5132.   else
  5133.     abort ();
  5134. }
  5135.  
  5136. static LWLIB_ID search_id;
  5137. static int last_search_up_p;
  5138.  
  5139. static void
  5140. hide_search_dialog (Widget w, LWLIB_ID id)
  5141. {
  5142. #if 0
  5143.   /* I'd like to do this, but the widget occasionally gets FUCKED */
  5144.   XUnmapWindow (XtDisplay (w), XtWindow (w));
  5145. #else
  5146.   lw_destroy_all_widgets (id);
  5147. #endif
  5148. }
  5149.  
  5150.  
  5151. static void
  5152. search_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
  5153. {
  5154.   Widget parent = widget;
  5155.   widget_value *data;
  5156.   char *name = (char *) client_data;
  5157.   Lisp_Object search, replace;
  5158.   Lisp_Object case_sensitive_p, regexp_p, direction, match_word_p;
  5159.  
  5160.   if ((int) client_data == -1) name = "done";    /* WM_DELETE_WINDOW */
  5161.  
  5162.   while (parent && XtClass (parent) != xmDialogShellWidgetClass)
  5163.     parent = XtParent (parent);
  5164.   if (! parent) abort ();
  5165.  
  5166.   if (!strcmp (name, "done"))
  5167.     {
  5168.       hide_search_dialog (parent, id);
  5169.       return;
  5170.     }
  5171. #if 0
  5172.   else if (!strcmp (name, "help"))
  5173.     {
  5174.       Lisp_Object v = Fmake_vector (3, Qt);
  5175.       vector_data (XVECTOR (v)) [0] = build_string ("ok");
  5176.       vector_data (XVECTOR (v)) [1] = list1 (Qignore);
  5177.       Fpopup_dialog_box (list2 (build_string ("dbx_search_help"), v));
  5178.       return;
  5179.     }
  5180. #endif
  5181.  
  5182.   {
  5183.     struct device *d = get_device_from_display (XtDisplay (widget));
  5184.     DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d);
  5185.   }
  5186.  
  5187.   if (!strcmp (name, "gotoStart"))
  5188.     {
  5189.       signal_special_Xt_user_event (Qcall_interactively, Qbeginning_of_buffer);
  5190.     }
  5191.   else if (!strcmp (name, "gotoEnd"))
  5192.     {
  5193.       signal_special_Xt_user_event (Qcall_interactively, Qend_of_buffer);
  5194.     }
  5195.   else if (!strcmp (name, "scrollForward"))
  5196.     {
  5197.       signal_special_Xt_user_event (Qcall_interactively, Qscroll_up);
  5198.     }
  5199.   else if (!strcmp (name, "scrollBack"))
  5200.     {
  5201.       signal_special_Xt_user_event (Qcall_interactively, Qdown_up);
  5202.     }
  5203.   else
  5204.     {
  5205.       data = malloc_widget_value ();
  5206.       data->name = "searchText";
  5207.       if (! lw_get_some_values (id, data)) abort ();
  5208.       search = build_string (data->value);
  5209.       data->name = "replaceText";
  5210.       if (! lw_get_some_values (id, data)) abort ();
  5211.       replace = build_string (data->value);
  5212.       data->name = "regexpSearch";
  5213.       if (! lw_get_some_values (id, data)) abort ();
  5214.       regexp_p = (data->selected ? Qt : Qnil);
  5215.       data->name = "caseSearch";
  5216.       if (! lw_get_some_values (id, data)) abort ();
  5217.       case_sensitive_p = (data->selected ? Qt : Qnil);
  5218.       data->name = "matchWord";
  5219.       if (! lw_get_some_values (id, data)) abort ();
  5220.       match_word_p = (data->selected ? Qt : Qnil);
  5221.       
  5222.       data->name = "directionForward";
  5223.       if (! lw_get_some_values (id, data)) abort ();
  5224.       direction = data->selected ? Qt : Qnil;
  5225.       
  5226.       if (!strcmp (name, "search"))
  5227.     replace = Qnil;
  5228.       else if (!strcmp (name, "replace"))
  5229.     ;
  5230.       else if (!strcmp (name, "replace_all"))
  5231.     {
  5232.       replace = list1 (replace);
  5233.       /*    hide_search_dialog (parent, id); */
  5234.     }
  5235.       else
  5236.     abort ();
  5237.       
  5238.       free_widget_value (data);
  5239.       
  5240.       signal_special_Xt_user_event (intern ("energize-search-internal"),
  5241.                  (NILP (replace)
  5242.                   ? list5 (case_sensitive_p, match_word_p,
  5243.                        regexp_p, direction, search)
  5244.                   : list6 (case_sensitive_p, match_word_p,
  5245.                        regexp_p, direction, search,
  5246.                        replace)));
  5247.     }
  5248. }
  5249.  
  5250.  
  5251. DEFUN ("energize-search", Fenergize_search, Senergize_search, 0, 0, "",
  5252.        "Pop up the search-and-replace dialog box.")
  5253.      ()
  5254. {
  5255.   int dbox_id;
  5256.   struct frame *f = XFRAME (Fselected_frame (Qnil));
  5257.   widget_value *data;
  5258.   Widget parent, dbox;
  5259.  
  5260.   if (!FRAME_IS_X (f)) error ("not an X frame");
  5261.   parent = FRAME_X_SHELL_WIDGET (f);
  5262.  
  5263.   data = malloc_widget_value ();
  5264.  
  5265.   dbox_id = (search_id ? search_id : new_lwlib_id());
  5266.   dbox = lw_create_widget ("search", "search", dbox_id, NULL, parent,
  5267.                1, 0, search_callback, 0);
  5268.   data->enabled = 1;
  5269.   data->value = 0;
  5270.  
  5271.   data->name = "button1"; data->value = data->call_data = "search";
  5272.   lw_modify_all_widgets (dbox_id, data, True);
  5273.   data->name = "button2"; data->value = data->call_data = "replace";
  5274.   lw_modify_all_widgets (dbox_id, data, True);
  5275.   data->name = "button3"; data->value = data->call_data = "replace_all";
  5276.   lw_modify_all_widgets (dbox_id, data, True);
  5277.   data->name = "button4"; data->value = data->call_data = "done";
  5278.   lw_modify_all_widgets (dbox_id, data, True);
  5279.  
  5280.   data->value = 0;
  5281.   data->name = data->call_data = "gotoStart";
  5282.   lw_modify_all_widgets (dbox_id, data, True);
  5283.   data->name = data->call_data = "gotoEnd";
  5284.   lw_modify_all_widgets (dbox_id, data, True);
  5285.   data->name = data->call_data = "scrollBack";
  5286.   lw_modify_all_widgets (dbox_id, data, True);
  5287.   data->name = data->call_data = "scrollForward";
  5288.   lw_modify_all_widgets (dbox_id, data, True);
  5289.  
  5290.   data->value = 0;
  5291.   data->name = data->call_data = "caseSearch";
  5292.   data->selected = NILP (current_buffer->case_fold_search);
  5293.   lw_modify_all_widgets (dbox_id, data, True);
  5294.  
  5295.   data->name = data->call_data = "directionForward";
  5296.   data->selected = 1;
  5297.   lw_modify_all_widgets (dbox_id, data, True);
  5298.   data->name = data->call_data = "directionBackward";
  5299.   data->selected = 0;
  5300.   lw_modify_all_widgets (dbox_id, data, True);
  5301.  
  5302.   free_widget_value (data);
  5303.  
  5304.   lw_pop_up_all_widgets (dbox_id);
  5305.   last_search_up_p = 0;
  5306.   if (search_id)
  5307.     {
  5308.       Widget w = lw_get_widget (dbox_id, parent, True);
  5309.       if (! w) abort ();
  5310.       XMapRaised (XtDisplay (w), XtWindow (w));
  5311.     }
  5312.   else
  5313.     {
  5314.       search_id = dbox_id;
  5315.     }
  5316.  
  5317.   return Qnil;
  5318. }
  5319.  
  5320.  
  5321.  
  5322. /*************** Definition of Emacs Lisp-callable functions ***************/
  5323.  
  5324. void
  5325. syms_of_energize (void)
  5326. {
  5327.   defsubr (&Senergize_send_buffer_modified);
  5328.   defsubr (&Senergize_list_menu);
  5329.   defsubr (&Senergize_execute_menu_item);
  5330.   defsubr (&Senergize_execute_command_internal);
  5331.   defsubr (&Sconnect_to_energize_internal);
  5332.   defsubr (&Sconnected_to_energize_p);
  5333.   defsubr (&Sclose_connection_to_energize);
  5334.   defsubr (&Shandle_energize_request);
  5335.   defsubr (&Senergize_buffer_p);
  5336.   defsubr (&Senergize_buffer_type);
  5337.   defsubr (&Sset_energize_buffer_type_internal);
  5338.   defsubr (&Senergize_buffer_id);
  5339.   defsubr (&Senergize_request_kill_buffer);
  5340.   defsubr (&Senergize_send_region);
  5341.   defsubr (&Senergize_user_input_buffer_mark);
  5342.   defsubr (&Senergize_update_menubar);
  5343.   defsubr (&Senergize_extent_menu_p);
  5344.   defsubr (&Senergize_query_buffer);
  5345.   defsubr (&Senergize_barf_if_buffer_locked);
  5346.   defsubr (&Senergize_psheets_visible_p);
  5347.   defsubr (&Senergize_buffer_has_psheets_p);
  5348.   defsubr (&Senergize_toggle_psheet);
  5349.   defsubr (&Senergize_protocol_level);
  5350.   defsubr (&Senergize_edit_mode_prompt);
  5351.   defsubr (&Senergize_search);
  5352.   defsubr (&Sextent_to_generic_id);
  5353.  
  5354.   defsymbol (&Qenergize_create_buffer_hook, "energize-create-buffer-hook");
  5355.   defsymbol (&Qenergize_buffer_modified_hook, "energize-buffer-modified-hook");
  5356.  
  5357.   defsymbol (&Qenergize_kernel_busy, "energize-kernel-busy");
  5358.  
  5359.   defsymbol (&Qenergize_kernel_busy_hook, "energize-kernel-busy-hook");
  5360.   defsymbol (&Qenergize_menu_update_hook, "energize-menu-update-hook");
  5361.   defsymbol (&Qbuffer_locked_by_energize, "buffer-locked-by-energize");
  5362.   defsymbol (&Qenergize_user_input_buffer_mark,
  5363.          "energize-user-input-buffer-mark");
  5364.   defsymbol (&Qenergize_make_many_buffers_visible,
  5365.          "energize-make-many-buffers-visible");
  5366.   defsymbol (&Qenergize, "energize");
  5367.   defsymbol (&Qenergize_auto_revert_buffer, "energize-auto-revert-buffer");
  5368. }
  5369.  
  5370. void
  5371. vars_of_energize (void)
  5372. {
  5373.   energize_connection = 0;
  5374.   inside_process_energize_request_1 = 0;
  5375.  
  5376.   staticpro (&Venergize_buffers_list);
  5377.   Venergize_buffers_list = Qnil;
  5378.  
  5379.   staticpro (&Vall_energize_pixmaps);
  5380.   Vall_energize_pixmaps = Qnil;
  5381.  
  5382.   Fprovide (intern ("energize"));
  5383.  
  5384.   search_id = 0;
  5385.  
  5386.   DEFVAR_LISP ("energize-process", &Venergize_process,
  5387.            "The Lisp object representing the Energize connection, or nil");
  5388.   Venergize_process = Qnil;
  5389.  
  5390.   DEFVAR_LISP ("energize-create-buffer-hook", &Venergize_create_buffer_hook,
  5391.            "Hook called when buffer is created by energize; takes \n\
  5392. BUFFER as its only argument.");
  5393.   Venergize_create_buffer_hook = Qnil;
  5394.  
  5395.  
  5396.   DEFVAR_LISP ("energize-kernel-modification-hook",
  5397.            &Venergize_kernel_modification_hook,
  5398.           "Hook called when a buffer is being modified by energize;\n\
  5399. takes no arguments.");
  5400.   Venergize_kernel_modification_hook = Qnil;
  5401.  
  5402.   DEFVAR_BOOL ("ignore-kernel",
  5403.            &ignore_kernel,
  5404.            "Set when the kernel should be ignored -- for debugging.");
  5405.   ignore_kernel = 0;
  5406.  
  5407.   DEFVAR_LISP ("energize-kernel-busy", &Venergize_kernel_busy,
  5408.            "True if the Energize kernel is busy.");
  5409.   Venergize_kernel_busy = Qnil;
  5410.   DEFVAR_LISP ("energize-kernel-busy-hook", &Venergize_kernel_busy_hook,
  5411.            "Hook called when the Energize kernel becomes busy or non busy.");
  5412.   Venergize_kernel_busy_hook = Qnil;
  5413.  
  5414.   DEFVAR_LISP ("energize-menu-update-hook", &Venergize_menu_update_hook,
  5415.            "Hook called when the Energize kernel updates the menubar.");
  5416.   Venergize_menu_update_hook = Qnil;
  5417.  
  5418.   DEFVAR_LISP ("energize-attributes-mapping", &Venergize_attributes_mapping,
  5419.            "A-list to map kernel attributes indexes to Emacs attributes");
  5420.   Venergize_attributes_mapping = Qnil;
  5421.  
  5422.   DEFVAR_INT ("energize-extent-gc-threshold", &energize_extent_gc_threshold,
  5423.           "Number of  extents in a ModifyBuffer request above which to do a GC");
  5424.   energize_extent_gc_threshold = 20;
  5425.   
  5426.   pure_put (Qbuffer_locked_by_energize, Qerror_conditions,
  5427.         list2 (Qbuffer_locked_by_energize, Qerror));
  5428.   pure_put (Qbuffer_locked_by_energize, Qerror_message,
  5429.         build_string ("Buffer is currently locked by kernel"));
  5430. }
  5431.  
  5432. void
  5433. complex_vars_of_energize (void)
  5434. {
  5435.   image_cache = make_strings_hashtable (50);
  5436. }
  5437.  
  5438. #endif /* ENERGIZE */
  5439.